Merge remote-tracking branch 'origin/master' into jetty-8
Conflicts: VERSION.txt example-jetty-embedded/pom.xml jetty-aggregate/jetty-all-server/pom.xml jetty-aggregate/jetty-all/pom.xml jetty-aggregate/jetty-client/pom.xml jetty-aggregate/jetty-plus/pom.xml jetty-aggregate/jetty-server/pom.xml jetty-aggregate/jetty-servlet/pom.xml jetty-aggregate/jetty-webapp/pom.xml jetty-aggregate/pom.xml jetty-ajp/pom.xml jetty-annotations/pom.xml jetty-client/pom.xml jetty-continuation/pom.xml jetty-deploy/pom.xml jetty-deploy/src/main/config/etc/jetty-deploy.xml jetty-distribution/pom.xml jetty-http/pom.xml jetty-io/pom.xml jetty-jaspi/pom.xml jetty-jmx/pom.xml jetty-jndi/pom.xml jetty-jsp-2.1/pom.xml jetty-monitor/pom.xml jetty-nested/pom.xml jetty-nosql/pom.xml jetty-osgi/jetty-osgi-boot-jsp/pom.xml jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java jetty-osgi/jetty-osgi-boot-logback/pom.xml jetty-osgi/jetty-osgi-boot-warurl/pom.xml jetty-osgi/jetty-osgi-boot/pom.xml jetty-osgi/jetty-osgi-equinoxtools/pom.xml jetty-osgi/jetty-osgi-httpservice/pom.xml jetty-osgi/jetty-osgi-servletbridge/pom.xml jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml jetty-osgi/pom.xml jetty-osgi/test-jetty-osgi/pom.xml jetty-overlay-deployer/pom.xml jetty-plus/pom.xml jetty-policy/pom.xml jetty-rewrite/pom.xml jetty-security/pom.xml jetty-server/pom.xml jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java jetty-servlet/pom.xml jetty-servlets/pom.xml jetty-start/pom.xml jetty-util/pom.xml jetty-webapp/pom.xml jetty-websocket/pom.xml jetty-xml/pom.xml pom.xml test-continuation-jetty6/pom.xml test-continuation/pom.xml test-jetty-nested/pom.xml test-jetty-servlet/pom.xml test-jetty-webapp/pom.xml tests/pom.xml tests/test-integration/pom.xml tests/test-loginservice/pom.xml tests/test-sessions/pom.xml tests/test-sessions/test-hash-sessions/pom.xml tests/test-sessions/test-jdbc-sessions/pom.xml tests/test-sessions/test-sessions-common/pom.xml tests/test-webapps/pom.xml tests/test-webapps/test-webapp-rfc2616/pom.xml
This commit is contained in:
commit
32dbb1bddb
|
@ -1,14 +1,33 @@
|
||||||
target/
|
# eclipse
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
|
|
||||||
|
# maven
|
||||||
|
target/
|
||||||
*/src/main/java/META-INF/
|
*/src/main/java/META-INF/
|
||||||
.pmd
|
|
||||||
|
# common junk
|
||||||
*.log
|
*.log
|
||||||
*.swp
|
*.swp
|
||||||
*.diff
|
*.diff
|
||||||
*.patch
|
*.patch
|
||||||
|
|
||||||
|
# intellij
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# Mac filesystem dust
|
||||||
|
/.DS_Store
|
||||||
|
|
||||||
|
# pmd
|
||||||
|
.pmdruleset
|
||||||
|
.pmd
|
||||||
|
|
||||||
|
# netbeans
|
||||||
|
/nbproject
|
||||||
|
|
||||||
|
# vim
|
||||||
|
.*.sw[a-p]
|
||||||
|
|
19
VERSION.txt
19
VERSION.txt
|
@ -1,5 +1,11 @@
|
||||||
jetty-8.0.2-SNAPSHOT
|
jetty-8.0.2-SNAPSHOT
|
||||||
|
|
||||||
|
|
||||||
|
jetty-7.5.2-SNAPSHOT
|
||||||
|
+ 358121 Implement new UTF8 Algorithm to UTF8Appendable.java
|
||||||
|
+ 353839 ajp component error when upload file
|
||||||
|
+ JETTY-1378 new system property to for the use of the JDTCompiler when using the latest jsp-impl
|
||||||
|
|
||||||
jetty-8.0.1.v20110908 - 08 September 2011
|
jetty-8.0.1.v20110908 - 08 September 2011
|
||||||
+ 350634 Added Resource.newResource(File)
|
+ 350634 Added Resource.newResource(File)
|
||||||
+ 356190 fix monodb tests for changed test api
|
+ 356190 fix monodb tests for changed test api
|
||||||
|
@ -12,12 +18,25 @@ jetty-8.0.1.v20110908 - 08 September 2011
|
||||||
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
||||||
+ 357058 Acceptor thread blocking
|
+ 357058 Acceptor thread blocking
|
||||||
|
|
||||||
|
jetty-7.5.1.v20110908 - 08 September 2011
|
||||||
|
+ 350634 Added Resource.newResource(File)
|
||||||
|
+ 356190 fix monodb tests for changed test api
|
||||||
|
+ 356428 removed timed waits from test
|
||||||
|
+ 356693 reduce visibility to webapp of websocket implementations
|
||||||
|
+ 356695 jetty server jars are provided for websockets
|
||||||
|
+ 356726 Instead of the sessionDestroyed called sessionCreated after
|
||||||
|
invalidate session
|
||||||
|
+ 356751 Add null protection to ServletContextHandler.doStop
|
||||||
|
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
||||||
|
+ 357058 Acceptor thread blocking
|
||||||
|
|
||||||
jetty-8.0.0.v20110901 - 01 September 2011
|
jetty-8.0.0.v20110901 - 01 September 2011
|
||||||
+ 352565 cookie httponly flag ignored
|
+ 352565 cookie httponly flag ignored
|
||||||
+ 353073 better warnings
|
+ 353073 better warnings
|
||||||
+ 353285 ServletSecurity annotation ignored
|
+ 353285 ServletSecurity annotation ignored
|
||||||
+ 356421 Upgraded websocket to draft 13 support
|
+ 356421 Upgraded websocket to draft 13 support
|
||||||
|
|
||||||
|
|
||||||
jetty-7.5.0.v20110901 - 01 September 2011
|
jetty-7.5.0.v20110901 - 01 September 2011
|
||||||
+ 356421 Upgraded websocket to draft 13 support
|
+ 356421 Upgraded websocket to draft 13 support
|
||||||
+ 353073 better warnings
|
+ 353073 better warnings
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
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.log.Log;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
|
||||||
|
@ -87,9 +88,15 @@ public class LikeJettyXml
|
||||||
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||||
"SSL_DHE_DSS_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);
|
ssl_connector.setStatsOn(true);
|
||||||
server.addConnector(ssl_connector);
|
server.addConnector(ssl_connector);
|
||||||
|
ssl_connector.open();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
|
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
|
||||||
ajp.setPort(8009);
|
ajp.setPort(8009);
|
||||||
server.addConnector(ajp);
|
server.addConnector(ajp);
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class SecuredHelloHandler
|
||||||
{
|
{
|
||||||
public static void main(String[] args) throws Exception
|
public static void main(String[] args) throws Exception
|
||||||
{
|
{
|
||||||
Server server = new Server(0);
|
Server server = new Server(8080);
|
||||||
|
|
||||||
LoginService loginService = new HashLoginService("MyRealm","src/test/resources/realm.properties");
|
LoginService loginService = new HashLoginService("MyRealm","src/test/resources/realm.properties");
|
||||||
server.addBean(loginService);
|
server.addBean(loginService);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<goal>unpack-dependencies</goal>
|
<goal>unpack-dependencies</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<includes>META-INF/**,org/eclipse/**</includes>
|
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||||
<overWriteReleases>false</overWriteReleases>
|
<overWriteReleases>false</overWriteReleases>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<goal>unpack-dependencies</goal>
|
<goal>unpack-dependencies</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<includes>META-INF/**,org/eclipse/**</includes>
|
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/*</includes>
|
||||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||||
<overWriteReleases>false</overWriteReleases>
|
<overWriteReleases>false</overWriteReleases>
|
||||||
|
@ -75,6 +75,19 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>javadoc-jar</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<goal>unpack-dependencies</goal>
|
<goal>unpack-dependencies</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<includes>META-INF/**,org/eclipse/**</includes>
|
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||||
<overWriteReleases>false</overWriteReleases>
|
<overWriteReleases>false</overWriteReleases>
|
||||||
|
|
|
@ -44,38 +44,38 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
byte[] xA001 =
|
byte[] xA001 =
|
||||||
{ (byte) 0xA0, (byte) 0x01 };
|
{ (byte)0xA0, (byte)0x01 };
|
||||||
byte[] xA002 =
|
byte[] xA002 =
|
||||||
{ (byte) 0xA0, (byte) 0x02 };
|
{ (byte)0xA0, (byte)0x02 };
|
||||||
byte[] xA003 =
|
byte[] xA003 =
|
||||||
{ (byte) 0xA0, (byte) 0x03 };
|
{ (byte)0xA0, (byte)0x03 };
|
||||||
byte[] xA004 =
|
byte[] xA004 =
|
||||||
{ (byte) 0xA0, (byte) 0x04 };
|
{ (byte)0xA0, (byte)0x04 };
|
||||||
byte[] xA005 =
|
byte[] xA005 =
|
||||||
{ (byte) 0xA0, (byte) 0x05 };
|
{ (byte)0xA0, (byte)0x05 };
|
||||||
byte[] xA006 =
|
byte[] xA006 =
|
||||||
{ (byte) 0xA0, (byte) 0x06 };
|
{ (byte)0xA0, (byte)0x06 };
|
||||||
byte[] xA007 =
|
byte[] xA007 =
|
||||||
{ (byte) 0xA0, (byte) 0x07 };
|
{ (byte)0xA0, (byte)0x07 };
|
||||||
byte[] xA008 =
|
byte[] xA008 =
|
||||||
{ (byte) 0xA0, (byte) 0x08 };
|
{ (byte)0xA0, (byte)0x08 };
|
||||||
byte[] xA009 =
|
byte[] xA009 =
|
||||||
{ (byte) 0xA0, (byte) 0x09 };
|
{ (byte)0xA0, (byte)0x09 };
|
||||||
byte[] xA00A =
|
byte[] xA00A =
|
||||||
{ (byte) 0xA0, (byte) 0x0A };
|
{ (byte)0xA0, (byte)0x0A };
|
||||||
byte[] xA00B =
|
byte[] xA00B =
|
||||||
{ (byte) 0xA0, (byte) 0x0B };
|
{ (byte)0xA0, (byte)0x0B };
|
||||||
__headerHash.put("Content-Type", xA001);
|
__headerHash.put("Content-Type",xA001);
|
||||||
__headerHash.put("Content-Language", xA002);
|
__headerHash.put("Content-Language",xA002);
|
||||||
__headerHash.put("Content-Length", xA003);
|
__headerHash.put("Content-Length",xA003);
|
||||||
__headerHash.put("Date", xA004);
|
__headerHash.put("Date",xA004);
|
||||||
__headerHash.put("Last-Modified", xA005);
|
__headerHash.put("Last-Modified",xA005);
|
||||||
__headerHash.put("Location", xA006);
|
__headerHash.put("Location",xA006);
|
||||||
__headerHash.put("Set-Cookie", xA007);
|
__headerHash.put("Set-Cookie",xA007);
|
||||||
__headerHash.put("Set-Cookie2", xA008);
|
__headerHash.put("Set-Cookie2",xA008);
|
||||||
__headerHash.put("Servlet-Engine", xA009);
|
__headerHash.put("Servlet-Engine",xA009);
|
||||||
__headerHash.put("Status", xA00A);
|
__headerHash.put("Status",xA00A);
|
||||||
__headerHash.put("WWW-Authenticate", xA00B);
|
__headerHash.put("WWW-Authenticate",xA00B);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
// 0, 1 ajp int 1 packet length
|
// 0, 1 ajp int 1 packet length
|
||||||
// 9 CPONG response Code
|
// 9 CPONG response Code
|
||||||
private static final byte[] AJP13_CPONG_RESPONSE =
|
private static final byte[] AJP13_CPONG_RESPONSE =
|
||||||
{ 'A', 'B', 0, 1, 9};
|
{ 'A', 'B', 0, 1, 9 };
|
||||||
|
|
||||||
private static final byte[] AJP13_END_RESPONSE =
|
private static final byte[] AJP13_END_RESPONSE =
|
||||||
{ 'A', 'B', 0, 2, 5, 1 };
|
{ 'A', 'B', 0, 2, 5, 1 };
|
||||||
|
@ -114,7 +114,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public Ajp13Generator(Buffers buffers, EndPoint io)
|
public Ajp13Generator(Buffers buffers, EndPoint io)
|
||||||
{
|
{
|
||||||
super(buffers, io);
|
super(buffers,io);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -130,6 +130,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public void reset(boolean returnBuffers)
|
public void reset(boolean returnBuffers)
|
||||||
|
@ -140,9 +141,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
_needMore = false;
|
_needMore = false;
|
||||||
_expectMore = false;
|
_expectMore = false;
|
||||||
_bufferPrepared = false;
|
_bufferPrepared = false;
|
||||||
_last=false;
|
_last = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_state = STATE_HEADER;
|
_state = STATE_HEADER;
|
||||||
|
|
||||||
|
@ -159,11 +158,9 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
_noContent = false;
|
_noContent = false;
|
||||||
_persistent = true;
|
_persistent = true;
|
||||||
|
|
||||||
|
_header = null; // Buffer for HTTP header (and maybe small _content)
|
||||||
|
_buffer = null; // Buffer for copy of passed _content
|
||||||
_header = null; // Buffer for HTTP header (and maybe small _content)
|
_content = null; // Buffer passed to addContent
|
||||||
_buffer = null; // Buffer for copy of passed _content
|
|
||||||
_content = null; // Buffer passed to addContent
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,13 +172,13 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
{
|
{
|
||||||
initContent();
|
initContent();
|
||||||
}
|
}
|
||||||
catch(IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return super.getContentBufferSize()-7;
|
return super.getContentBufferSize() - 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public void increaseContentBufferSize(int contentBufferSize)
|
public void increaseContentBufferSize(int contentBufferSize)
|
||||||
|
@ -196,11 +193,9 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
* @param content
|
* @param content
|
||||||
* @param last
|
* @param last
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if <code>content</code> is
|
* if <code>content</code> is {@link Buffer#isImmutable immutable}.
|
||||||
* {@link Buffer#isImmutable immutable}.
|
|
||||||
* @throws IllegalStateException
|
* @throws IllegalStateException
|
||||||
* If the request is not expecting any more content, or if the
|
* If the request is not expecting any more content, or if the buffers are full and cannot be flushed.
|
||||||
* buffers are full and cannot be flushed.
|
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* if there is a problem flushing the buffers.
|
* if there is a problem flushing the buffers.
|
||||||
*/
|
*/
|
||||||
|
@ -217,13 +212,13 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
|
|
||||||
if (_last || _state == STATE_END)
|
if (_last || _state == STATE_END)
|
||||||
{
|
{
|
||||||
LOG.debug("Ignoring extra content {}", content);
|
LOG.debug("Ignoring extra content {}",content);
|
||||||
content.clear();
|
content.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_last = last;
|
_last = last;
|
||||||
|
|
||||||
if(!_endp.isOpen())
|
if (!_endp.isOpen())
|
||||||
{
|
{
|
||||||
_state = STATE_END;
|
_state = STATE_END;
|
||||||
return;
|
return;
|
||||||
|
@ -289,8 +284,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
if (_last || _state == STATE_END)
|
if (_last || _state == STATE_END)
|
||||||
throw new IllegalStateException("Closed");
|
throw new IllegalStateException("Closed");
|
||||||
|
|
||||||
|
if (!_endp.isOpen())
|
||||||
if(!_endp.isOpen())
|
|
||||||
{
|
{
|
||||||
_state = STATE_END;
|
_state = STATE_END;
|
||||||
return false;
|
return false;
|
||||||
|
@ -322,8 +316,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Prepare buffer for unchecked writes. Prepare the generator buffer to
|
* Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
|
||||||
* receive unchecked writes
|
|
||||||
*
|
*
|
||||||
* @return the available space in the buffer.
|
* @return the available space in the buffer.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
@ -337,8 +330,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
if (_last || _state == STATE_END)
|
if (_last || _state == STATE_END)
|
||||||
throw new IllegalStateException("Closed");
|
throw new IllegalStateException("Closed");
|
||||||
|
|
||||||
|
if (!_endp.isOpen())
|
||||||
if(!_endp.isOpen())
|
|
||||||
{
|
{
|
||||||
_state = STATE_END;
|
_state = STATE_END;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -377,8 +369,8 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
_last = _last | allContentAdded;
|
_last = _last | allContentAdded;
|
||||||
|
|
||||||
boolean has_server = false;
|
boolean has_server = false;
|
||||||
if (_persistent==null)
|
if (_persistent == null)
|
||||||
_persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
|
_persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||||
|
|
||||||
// get a header buffer
|
// get a header buffer
|
||||||
if (_header == null)
|
if (_header == null)
|
||||||
|
@ -390,13 +382,13 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// start the header
|
// start the header
|
||||||
_buffer.put((byte) 'A');
|
_buffer.put((byte)'A');
|
||||||
_buffer.put((byte) 'B');
|
_buffer.put((byte)'B');
|
||||||
addInt(0);
|
addInt(0);
|
||||||
_buffer.put((byte) 0x4);
|
_buffer.put((byte)0x4);
|
||||||
addInt(_status);
|
addInt(_status);
|
||||||
if (_reason == null)
|
if (_reason == null)
|
||||||
_reason=HttpGenerator.getReasonBuffer(_status);
|
_reason = HttpGenerator.getReasonBuffer(_status);
|
||||||
if (_reason == null)
|
if (_reason == null)
|
||||||
_reason = new ByteArrayBuffer(Integer.toString(_status));
|
_reason = new ByteArrayBuffer(Integer.toString(_status));
|
||||||
addBuffer(_reason);
|
addBuffer(_reason);
|
||||||
|
@ -407,7 +399,6 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
_content = null;
|
_content = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// allocate 2 bytes for number of headers
|
// allocate 2 bytes for number of headers
|
||||||
int field_index = _buffer.putIndex();
|
int field_index = _buffer.putIndex();
|
||||||
addInt(0);
|
addInt(0);
|
||||||
|
@ -417,15 +408,15 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
if (fields != null)
|
if (fields != null)
|
||||||
{
|
{
|
||||||
// Add headers
|
// Add headers
|
||||||
int s=fields.size();
|
int s = fields.size();
|
||||||
for (int f=0;f<s;f++)
|
for (int f = 0; f < s; f++)
|
||||||
{
|
{
|
||||||
HttpFields.Field field = fields.getField(f);
|
HttpFields.Field field = fields.getField(f);
|
||||||
if (field==null)
|
if (field == null)
|
||||||
continue;
|
continue;
|
||||||
num_fields++;
|
num_fields++;
|
||||||
|
|
||||||
byte[] codes = (byte[]) __headerHash.get(field.getName());
|
byte[] codes = (byte[])__headerHash.get(field.getName());
|
||||||
if (codes != null)
|
if (codes != null)
|
||||||
{
|
{
|
||||||
_buffer.put(codes);
|
_buffer.put(codes);
|
||||||
|
@ -460,14 +451,13 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
// insert the total packet size on 2nd and 3rd byte that
|
// insert the total packet size on 2nd and 3rd byte that
|
||||||
// was previously
|
// was previously
|
||||||
// allocated
|
// allocated
|
||||||
addInt(2, payloadSize);
|
addInt(2,payloadSize);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_buffer = tmpbuf;
|
_buffer = tmpbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_state = STATE_CONTENT;
|
_state = STATE_CONTENT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -501,7 +491,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_state == STATE_HEADER && !_expectMore)
|
if (_state == STATE_HEADER && !_expectMore)
|
||||||
throw new IllegalStateException("State==HEADER");
|
throw new IllegalStateException("State==HEADER");
|
||||||
prepareBuffers();
|
prepareBuffers();
|
||||||
|
|
||||||
|
@ -528,90 +518,87 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
Flushing: while (true)
|
Flushing: while (true)
|
||||||
{
|
{
|
||||||
int len = -1;
|
int len = -1;
|
||||||
int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
|
int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
|
||||||
|
|
||||||
|
|
||||||
switch (to_flush)
|
switch (to_flush)
|
||||||
{
|
{
|
||||||
case 7:
|
case 7:
|
||||||
throw new IllegalStateException(); // should
|
throw new IllegalStateException(); // should
|
||||||
// never
|
// never
|
||||||
// happen!
|
// happen!
|
||||||
case 6:
|
case 6:
|
||||||
len = _endp.flush(_header, _buffer, null);
|
len = _endp.flush(_header,_buffer,null);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
throw new IllegalStateException(); // should
|
throw new IllegalStateException(); // should
|
||||||
// never
|
// never
|
||||||
// happen!
|
// happen!
|
||||||
case 4:
|
case 4:
|
||||||
len = _endp.flush(_header);
|
len = _endp.flush(_header);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
throw new IllegalStateException(); // should
|
throw new IllegalStateException(); // should
|
||||||
// never
|
// never
|
||||||
// happen!
|
// happen!
|
||||||
case 2:
|
case 2:
|
||||||
len = _endp.flush(_buffer);
|
len = _endp.flush(_buffer);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
throw new IllegalStateException(); // should
|
throw new IllegalStateException(); // should
|
||||||
// never
|
// never
|
||||||
// happen!
|
// happen!
|
||||||
case 0:
|
case 0:
|
||||||
{
|
|
||||||
// Nothing more we can write now.
|
|
||||||
if (_header != null)
|
|
||||||
_header.clear();
|
|
||||||
|
|
||||||
_bufferPrepared = false;
|
|
||||||
|
|
||||||
if (_buffer != null)
|
|
||||||
{
|
{
|
||||||
_buffer.clear();
|
// Nothing more we can write now.
|
||||||
|
if (_header != null)
|
||||||
|
_header.clear();
|
||||||
|
|
||||||
// reserve some space for the
|
_bufferPrepared = false;
|
||||||
// header
|
|
||||||
_buffer.setPutIndex(7);
|
|
||||||
_buffer.setGetIndex(7);
|
|
||||||
|
|
||||||
// Special case handling for
|
if (_buffer != null)
|
||||||
// small left over buffer from
|
|
||||||
// an addContent that caused a
|
|
||||||
// buffer flush.
|
|
||||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
|
||||||
{
|
{
|
||||||
|
_buffer.clear();
|
||||||
|
|
||||||
|
// reserve some space for the
|
||||||
|
// header
|
||||||
|
_buffer.setPutIndex(7);
|
||||||
|
_buffer.setGetIndex(7);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
break Flushing;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we completely finished for now?
|
||||||
|
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
||||||
|
{
|
||||||
|
if (_state == STATE_FLUSHING)
|
||||||
|
_state = STATE_END;
|
||||||
|
|
||||||
|
// if (_state == STATE_END)
|
||||||
|
// {
|
||||||
|
// _endp.close();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
_buffer.put(_content);
|
|
||||||
_content.clear();
|
|
||||||
_content = null;
|
|
||||||
break Flushing;
|
break Flushing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to prepare more to write.
|
||||||
|
prepareBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Are we completely finished for now?
|
|
||||||
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
|
||||||
{
|
|
||||||
if (_state == STATE_FLUSHING)
|
|
||||||
_state = STATE_END;
|
|
||||||
|
|
||||||
// if (_state == STATE_END)
|
|
||||||
// {
|
|
||||||
// _endp.close();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
break Flushing;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to prepare more to write.
|
|
||||||
prepareBuffers();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we failed to flush anything twice in a row
|
// If we failed to flush anything twice in a row
|
||||||
|
@ -631,7 +618,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOG.ignore(e);
|
LOG.ignore(e);
|
||||||
throw (e instanceof EofException) ? e : new EofException(e);
|
throw (e instanceof EofException)?e:new EofException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -680,14 +667,14 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
{
|
{
|
||||||
_bufferPrepared = true;
|
_bufferPrepared = true;
|
||||||
|
|
||||||
_buffer.put((byte) 0);
|
_buffer.put((byte)0);
|
||||||
int put = _buffer.putIndex();
|
int put = _buffer.putIndex();
|
||||||
_buffer.setGetIndex(0);
|
_buffer.setGetIndex(0);
|
||||||
_buffer.setPutIndex(0);
|
_buffer.setPutIndex(0);
|
||||||
_buffer.put((byte) 'A');
|
_buffer.put((byte)'A');
|
||||||
_buffer.put((byte) 'B');
|
_buffer.put((byte)'B');
|
||||||
addInt(payloadSize + 4);
|
addInt(payloadSize + 4);
|
||||||
_buffer.put((byte) 3);
|
_buffer.put((byte)3);
|
||||||
addInt(payloadSize);
|
addInt(payloadSize);
|
||||||
_buffer.setPutIndex(put);
|
_buffer.setPutIndex(put);
|
||||||
}
|
}
|
||||||
|
@ -759,15 +746,15 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void addInt(int i)
|
private void addInt(int i)
|
||||||
{
|
{
|
||||||
_buffer.put((byte) ((i >> 8) & 0xFF));
|
_buffer.put((byte)((i >> 8) & 0xFF));
|
||||||
_buffer.put((byte) (i & 0xFF));
|
_buffer.put((byte)(i & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void addInt(int startIndex, int i)
|
private void addInt(int startIndex, int i)
|
||||||
{
|
{
|
||||||
_buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
|
_buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
|
||||||
_buffer.poke((startIndex + 1), (byte) (i & 0xFF));
|
_buffer.poke((startIndex + 1),(byte)(i & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -786,7 +773,7 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
addInt(b.length);
|
addInt(b.length);
|
||||||
|
|
||||||
_buffer.put(b);
|
_buffer.put(b);
|
||||||
_buffer.put((byte) 0);
|
_buffer.put((byte)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -800,15 +787,14 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
|
|
||||||
addInt(b.length());
|
addInt(b.length());
|
||||||
_buffer.put(b);
|
_buffer.put(b);
|
||||||
_buffer.put((byte) 0);
|
_buffer.put((byte)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void getBodyChunk() throws IOException
|
public void getBodyChunk() throws IOException
|
||||||
{
|
{
|
||||||
_needMore = true;
|
ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
|
||||||
_expectMore = true;
|
_endp.flush(bf);
|
||||||
flushBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -818,7 +804,6 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
_expectMore = false;
|
_expectMore = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void sendCPong() throws IOException
|
public void sendCPong() throws IOException
|
||||||
{
|
{
|
||||||
|
@ -831,13 +816,11 @@ public class Ajp13Generator extends AbstractGenerator
|
||||||
{
|
{
|
||||||
_endp.flush(buff);
|
_endp.flush(buff);
|
||||||
}
|
}
|
||||||
while(buff.length() >0);
|
while (buff.length() > 0);
|
||||||
_buffers.returnBuffer(buff);
|
_buffers.returnBuffer(buff);
|
||||||
|
|
||||||
reset(true);
|
reset(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,10 +178,19 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return the threadPool
|
* @return the threadpool
|
||||||
*/
|
*/
|
||||||
public ThreadPool getThreadPool()
|
public ThreadPool getThreadPool()
|
||||||
{
|
{
|
||||||
|
if (_threadPool==null)
|
||||||
|
{
|
||||||
|
QueuedThreadPool pool = new QueuedThreadPool();
|
||||||
|
pool.setMaxThreads(16);
|
||||||
|
pool.setDaemon(true);
|
||||||
|
pool.setName("HttpClient");
|
||||||
|
_threadPool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
return _threadPool;
|
return _threadPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,13 +429,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
||||||
_idleTimeoutQ.setNow();
|
_idleTimeoutQ.setNow();
|
||||||
|
|
||||||
if (_threadPool == null)
|
if (_threadPool == null)
|
||||||
{
|
getThreadPool();
|
||||||
QueuedThreadPool pool = new QueuedThreadPool();
|
|
||||||
pool.setMaxThreads(16);
|
|
||||||
pool.setDaemon(true);
|
|
||||||
pool.setName("HttpClient");
|
|
||||||
_threadPool = pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_threadPool instanceof LifeCycle)
|
if (_threadPool instanceof LifeCycle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -353,8 +353,23 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
complete = true;
|
complete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the endpoint is closed, but the parser incomplete
|
||||||
|
if (!_endp.isOpen() && !(_parser.isComplete()||_parser.isIdle()))
|
||||||
|
{
|
||||||
|
// we wont be called again so let the parser see the close
|
||||||
|
complete=true;
|
||||||
|
_parser.parseAvailable();
|
||||||
|
if (!(_parser.isComplete()||_parser.isIdle()))
|
||||||
|
{
|
||||||
|
LOG.warn("Incomplete {} {}",_parser,_endp);
|
||||||
|
if (_exchange!=null)
|
||||||
|
_exchange.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO - is this needed ?
|
||||||
if (_generator.isComplete() && !_parser.isComplete())
|
if (_generator.isComplete() && !_parser.isComplete())
|
||||||
{
|
{
|
||||||
if (!_endp.isOpen() || _endp.isInputShutdown())
|
if (!_endp.isOpen() || _endp.isInputShutdown())
|
||||||
|
@ -364,6 +379,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if (complete || failed)
|
if (complete || failed)
|
||||||
{
|
{
|
||||||
|
@ -433,7 +449,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
_parser.returnBuffers();
|
_parser.returnBuffers();
|
||||||
|
|
||||||
// Do we have more stuff to write?
|
// Do we have more stuff to write?
|
||||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp instanceof AsyncEndPoint)
|
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp.isOpen() && _endp instanceof AsyncEndPoint)
|
||||||
{
|
{
|
||||||
// Assume we are write blocked!
|
// Assume we are write blocked!
|
||||||
((AsyncEndPoint)_endp).scheduleWrite();
|
((AsyncEndPoint)_endp).scheduleWrite();
|
||||||
|
@ -669,6 +685,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
case HttpExchange.STATUS_EXCEPTED:
|
case HttpExchange.STATUS_EXCEPTED:
|
||||||
case HttpExchange.STATUS_EXPIRED:
|
case HttpExchange.STATUS_EXPIRED:
|
||||||
break;
|
break;
|
||||||
|
case HttpExchange.STATUS_PARSING_CONTENT:
|
||||||
|
if (_endp.isInputShutdown() && _parser.isState(HttpParser.STATE_EOF_CONTENT))
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
String exch= exchange.toString();
|
String exch= exchange.toString();
|
||||||
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
||||||
|
|
|
@ -584,7 +584,7 @@ public class HttpDestination implements Dumpable
|
||||||
@Override
|
@Override
|
||||||
public synchronized String toString()
|
public synchronized String toString()
|
||||||
{
|
{
|
||||||
return "HttpDestination@" + hashCode() + "//" + _address.getHost() + ":" + _address.getPort() + "(" + _connections.size() + "," + _idle.size() + "," + _queue.size() + ")";
|
return String.format("HttpDestination@%x//%s:%d(%d/%d,%d,%d/%d)%n",hashCode(),_address.getHost(),_address.getPort(),_connections.size(),_maxConnections,_idle.size(),_queue.size(),_maxQueueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String toDetailString()
|
public synchronized String toDetailString()
|
||||||
|
|
|
@ -35,7 +35,9 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.Timeout;
|
import org.eclipse.jetty.util.thread.Timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.</p>
|
* <p>
|
||||||
|
* An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* This object encapsulates:
|
* This object encapsulates:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -48,23 +50,25 @@ import org.eclipse.jetty.util.thread.Timeout;
|
||||||
* <li>The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
|
* <li>The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>The HttpExchange class is intended to be used by a developer wishing to have close asynchronous
|
* <p>
|
||||||
* interaction with the the exchange.<br />
|
* The HttpExchange class is intended to be used by a developer wishing to have close asynchronous interaction with the the exchange.<br />
|
||||||
* Typically a developer will extend the HttpExchange class with a derived
|
* Typically a developer will extend the HttpExchange class with a derived class that overrides some or all of the onXxx callbacks. <br />
|
||||||
* class that overrides some or all of the onXxx callbacks. <br />
|
* There are also some predefined HttpExchange subtypes that can be used as a basis, see {@link org.eclipse.jetty.client.ContentExchange} and
|
||||||
* There are also some predefined HttpExchange subtypes that can be used as a basis,
|
* {@link org.eclipse.jetty.client.CachedExchange}.
|
||||||
* see {@link org.eclipse.jetty.client.ContentExchange} and {@link org.eclipse.jetty.client.CachedExchange}.</p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in
|
* <p>
|
||||||
* turn selects a {@link HttpDestination} and calls its {@link HttpDestination#send(HttpExchange)}, which
|
* Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in turn selects a {@link HttpDestination} and calls its
|
||||||
* then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}.
|
* {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}. A
|
||||||
* A developer may wish to directly call send on the destination or connection if they wish to bypass
|
* 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
|
||||||
* some handling provided (eg Cookie handling in the HttpDestination).</p>
|
* HttpDestination).
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed
|
* <p>
|
||||||
* pipeline request, authentication retry or redirection). In such cases, the HttpClient and/or HttpDestination
|
* In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed pipeline request, authentication retry or redirection).
|
||||||
* may insert their own HttpExchangeListener to intercept and filter the call backs intended for the
|
* In such cases, the HttpClient and/or HttpDestination may insert their own HttpExchangeListener to intercept and filter the call backs intended for the
|
||||||
* HttpExchange.</p>
|
* HttpExchange.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class HttpExchange
|
public class HttpExchange
|
||||||
{
|
{
|
||||||
|
@ -106,9 +110,10 @@ public class HttpExchange
|
||||||
// a timeout for this exchange
|
// a timeout for this exchange
|
||||||
private long _timeout = -1;
|
private long _timeout = -1;
|
||||||
private volatile Timeout.Task _timeoutTask;
|
private volatile Timeout.Task _timeoutTask;
|
||||||
|
private long _lastStateChange=System.currentTimeMillis();
|
||||||
private long _lastStateChange=-1;
|
|
||||||
private long _sent=-1;
|
private long _sent=-1;
|
||||||
|
private int _lastState=-1;
|
||||||
|
private int _lastStatePeriod=-1;
|
||||||
|
|
||||||
boolean _onRequestCompleteDone;
|
boolean _onRequestCompleteDone;
|
||||||
boolean _onResponseCompleteDone;
|
boolean _onResponseCompleteDone;
|
||||||
|
@ -131,8 +136,10 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param status the status to wait for
|
* @param status
|
||||||
* @throws InterruptedException if the waiting thread is interrupted
|
* the status to wait for
|
||||||
|
* @throws InterruptedException
|
||||||
|
* if the waiting thread is interrupted
|
||||||
* @deprecated Use {@link #waitForDone()} instead
|
* @deprecated Use {@link #waitForDone()} instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -142,21 +149,17 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait until the exchange is "done".
|
* Wait until the exchange is "done". Done is defined as when a final state has been passed to the HttpExchange via the associated onXxx call. Note that an
|
||||||
* Done is defined as when a final state has been passed to the
|
* exchange can transit a final state when being used as part of a dialog (eg {@link SecurityListener}. Done status is thus defined as:
|
||||||
* HttpExchange via the associated onXxx call. Note that an
|
*
|
||||||
* exchange can transit a final state when being used as part
|
* <pre>
|
||||||
* of a dialog (eg {@link SecurityListener}. Done status
|
* done == onConnectionFailed || onException || onExpire || onRequestComplete && onResponseComplete
|
||||||
* is thus defined as:<pre>
|
|
||||||
* done == onConnectionFailed
|
|
||||||
* || onException
|
|
||||||
* || onExpire
|
|
||||||
* || onRequestComplete && onResponseComplete
|
|
||||||
* </pre>
|
* </pre>
|
||||||
|
*
|
||||||
* @return the done status
|
* @return the done status
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public int waitForDone () throws InterruptedException
|
public int waitForDone() throws InterruptedException
|
||||||
{
|
{
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
|
@ -170,12 +173,12 @@ public class HttpExchange
|
||||||
{
|
{
|
||||||
// TODO - this should do a cancel and wakeup everybody that was waiting.
|
// TODO - this should do a cancel and wakeup everybody that was waiting.
|
||||||
// might need a version number concept
|
// might need a version number concept
|
||||||
synchronized(this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
_timeoutTask=null;
|
_timeoutTask = null;
|
||||||
_onRequestCompleteDone=false;
|
_onRequestCompleteDone = false;
|
||||||
_onResponseCompleteDone=false;
|
_onResponseCompleteDone = false;
|
||||||
_onDone=false;
|
_onDone = false;
|
||||||
setStatus(STATUS_START);
|
setStatus(STATUS_START);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,13 +189,16 @@ public class HttpExchange
|
||||||
{
|
{
|
||||||
int oldStatus = _status.get();
|
int oldStatus = _status.get();
|
||||||
boolean set = false;
|
boolean set = false;
|
||||||
if (oldStatus!=newStatus)
|
if (oldStatus != newStatus)
|
||||||
{
|
{
|
||||||
_lastStateChange=System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
_lastStatePeriod=(int)(now-_lastStateChange);
|
||||||
|
_lastState=oldStatus;
|
||||||
|
_lastStateChange=now;
|
||||||
if (newStatus==STATUS_SENDING_REQUEST)
|
if (newStatus==STATUS_SENDING_REQUEST)
|
||||||
_sent=_lastStateChange;
|
_sent=_lastStateChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
// State machine: from which old status you can go into which new status
|
// State machine: from which old status you can go into which new status
|
||||||
switch (oldStatus)
|
switch (oldStatus)
|
||||||
{
|
{
|
||||||
|
@ -204,7 +210,10 @@ public class HttpExchange
|
||||||
case STATUS_WAITING_FOR_COMMIT:
|
case STATUS_WAITING_FOR_COMMIT:
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
|
break;
|
||||||
|
case STATUS_EXPIRED:
|
||||||
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -214,11 +223,10 @@ public class HttpExchange
|
||||||
case STATUS_WAITING_FOR_COMMIT:
|
case STATUS_WAITING_FOR_COMMIT:
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -228,11 +236,10 @@ public class HttpExchange
|
||||||
case STATUS_SENDING_REQUEST:
|
case STATUS_SENDING_REQUEST:
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -240,16 +247,15 @@ public class HttpExchange
|
||||||
switch (newStatus)
|
switch (newStatus)
|
||||||
{
|
{
|
||||||
case STATUS_WAITING_FOR_RESPONSE:
|
case STATUS_WAITING_FOR_RESPONSE:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||||
getEventListener().onRequestCommitted();
|
getEventListener().onRequestCommitted();
|
||||||
break;
|
break;
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -259,11 +265,10 @@ public class HttpExchange
|
||||||
case STATUS_PARSING_HEADERS:
|
case STATUS_PARSING_HEADERS:
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -271,16 +276,15 @@ public class HttpExchange
|
||||||
switch (newStatus)
|
switch (newStatus)
|
||||||
{
|
{
|
||||||
case STATUS_PARSING_CONTENT:
|
case STATUS_PARSING_CONTENT:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||||
getEventListener().onResponseHeaderComplete();
|
getEventListener().onResponseHeaderComplete();
|
||||||
break;
|
break;
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -288,16 +292,15 @@ public class HttpExchange
|
||||||
switch (newStatus)
|
switch (newStatus)
|
||||||
{
|
{
|
||||||
case STATUS_COMPLETED:
|
case STATUS_COMPLETED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||||
getEventListener().onResponseComplete();
|
getEventListener().onResponseComplete();
|
||||||
break;
|
break;
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
set = setStatusExpired(newStatus,oldStatus);
|
||||||
getEventListener().onExpire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -307,12 +310,12 @@ public class HttpExchange
|
||||||
case STATUS_START:
|
case STATUS_START:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
case STATUS_WAITING_FOR_RESPONSE:
|
case STATUS_WAITING_FOR_RESPONSE:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
case STATUS_EXPIRED:
|
case STATUS_EXPIRED:
|
||||||
// Don't change the status, it's too late
|
// Don't change the status, it's too late
|
||||||
set=true;
|
set = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -321,12 +324,12 @@ public class HttpExchange
|
||||||
{
|
{
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
case STATUS_CANCELLED:
|
case STATUS_CANCELLED:
|
||||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||||
done();
|
done();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Ignore other statuses, we're cancelling
|
// Ignore other statuses, we're cancelling
|
||||||
set=true;
|
set = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -336,10 +339,10 @@ public class HttpExchange
|
||||||
switch (newStatus)
|
switch (newStatus)
|
||||||
{
|
{
|
||||||
case STATUS_START:
|
case STATUS_START:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set = _status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
set=true;
|
set = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -357,6 +360,14 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean setStatusExpired(int newStatus, int oldStatus)
|
||||||
|
{
|
||||||
|
boolean set;
|
||||||
|
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||||
|
getEventListener().onExpire();
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDone()
|
public boolean isDone()
|
||||||
{
|
{
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
|
@ -369,7 +380,7 @@ public class HttpExchange
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean isDone (int status)
|
public boolean isDone(int status)
|
||||||
{
|
{
|
||||||
return isDone();
|
return isDone();
|
||||||
}
|
}
|
||||||
|
@ -381,10 +392,10 @@ public class HttpExchange
|
||||||
|
|
||||||
public void setEventListener(HttpEventListener listener)
|
public void setEventListener(HttpEventListener listener)
|
||||||
{
|
{
|
||||||
_listener=listener;
|
_listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeout( long timeout )
|
public void setTimeout(long timeout)
|
||||||
{
|
{
|
||||||
_timeout = timeout;
|
_timeout = timeout;
|
||||||
}
|
}
|
||||||
|
@ -395,7 +406,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param url an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
* @param url
|
||||||
|
* an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
||||||
*/
|
*/
|
||||||
public void setURL(String url)
|
public void setURL(String url)
|
||||||
{
|
{
|
||||||
|
@ -403,7 +415,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param address the address of the server
|
* @param address
|
||||||
|
* the address of the server
|
||||||
*/
|
*/
|
||||||
public void setAddress(Address address)
|
public void setAddress(Address address)
|
||||||
{
|
{
|
||||||
|
@ -421,8 +434,7 @@ public class HttpExchange
|
||||||
/**
|
/**
|
||||||
* the local address used by the connection
|
* the local address used by the connection
|
||||||
*
|
*
|
||||||
* Note: this method will not be populated unless the exchange
|
* Note: this method will not be populated unless the exchange has been executed by the HttpClient
|
||||||
* has been executed by the HttpClient
|
|
||||||
*
|
*
|
||||||
* @return the local address used for the running of the exchange if available, null otherwise.
|
* @return the local address used for the running of the exchange if available, null otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -432,15 +444,17 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scheme the scheme of the URL (for example 'http')
|
* @param scheme
|
||||||
|
* the scheme of the URL (for example 'http')
|
||||||
*/
|
*/
|
||||||
public void setScheme(Buffer scheme)
|
public void setScheme(Buffer scheme)
|
||||||
{
|
{
|
||||||
_scheme = scheme;
|
_scheme = scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scheme the scheme of the URL (for example 'http')
|
* @param scheme
|
||||||
|
* the scheme of the URL (for example 'http')
|
||||||
*/
|
*/
|
||||||
public void setScheme(String scheme)
|
public void setScheme(String scheme)
|
||||||
{
|
{
|
||||||
|
@ -464,7 +478,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param version the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
* @param version
|
||||||
|
* the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
||||||
*/
|
*/
|
||||||
public void setVersion(int version)
|
public void setVersion(int version)
|
||||||
{
|
{
|
||||||
|
@ -472,7 +487,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param version the HTTP protocol version as string
|
* @param version
|
||||||
|
* the HTTP protocol version as string
|
||||||
*/
|
*/
|
||||||
public void setVersion(String version)
|
public void setVersion(String version)
|
||||||
{
|
{
|
||||||
|
@ -493,7 +509,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param method the HTTP method (for example 'GET')
|
* @param method
|
||||||
|
* the HTTP method (for example 'GET')
|
||||||
*/
|
*/
|
||||||
public void setMethod(String method)
|
public void setMethod(String method)
|
||||||
{
|
{
|
||||||
|
@ -528,9 +545,10 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request URI
|
* Set the request URI
|
||||||
*
|
*
|
||||||
* @param uri new request URI
|
* @param uri
|
||||||
|
* new request URI
|
||||||
* @see #setRequestURI(String)
|
* @see #setRequestURI(String)
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@ -541,36 +559,41 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request URI
|
* Set the request URI
|
||||||
*
|
*
|
||||||
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority<br/>
|
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority<br/>
|
||||||
* where:<br/><br/>
|
* where:<br/>
|
||||||
* "*" - request applies to server itself<br/>
|
* <br/>
|
||||||
|
* "*" - request applies to server itself<br/>
|
||||||
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context<br/>
|
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context<br/>
|
||||||
* (this form is generated automatically by HttpClient)<br/>
|
* (this form is generated automatically by HttpClient)<br/>
|
||||||
* abs_path - used for most methods, e.g. /context<br/>
|
* abs_path - used for most methods, e.g. /context<br/>
|
||||||
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
||||||
* <br/>
|
* <br/>
|
||||||
* For complete definition of URI components, see RFC 2396 sec3.<br/>
|
* For complete definition of URI components, see RFC 2396 sec3.<br/>
|
||||||
*
|
*
|
||||||
* @param uri new request URI
|
* @param uri
|
||||||
|
* new request URI
|
||||||
*/
|
*/
|
||||||
public void setRequestURI(String uri)
|
public void setRequestURI(String uri)
|
||||||
{
|
{
|
||||||
_uri = uri;
|
_uri = uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @param uri an absolute URI (for example 'http://localhost/foo/bar?a=1')
|
* @param uri
|
||||||
|
* an absolute URI (for example 'http://localhost/foo/bar?a=1')
|
||||||
*/
|
*/
|
||||||
public void setURI(URI uri)
|
public void setURI(URI uri)
|
||||||
{
|
{
|
||||||
if (!uri.isAbsolute())
|
if (!uri.isAbsolute())
|
||||||
throw new IllegalArgumentException("!Absolute URI: "+uri);
|
throw new IllegalArgumentException("!Absolute URI: " + uri);
|
||||||
|
|
||||||
if (uri.isOpaque())
|
if (uri.isOpaque())
|
||||||
throw new IllegalArgumentException("Opaque URI: "+uri);
|
throw new IllegalArgumentException("Opaque URI: " + uri);
|
||||||
|
|
||||||
|
LOG.debug("URI = {}",uri.toASCIIString());
|
||||||
|
|
||||||
String scheme = uri.getScheme();
|
String scheme = uri.getScheme();
|
||||||
int port = uri.getPort();
|
int port = uri.getPort();
|
||||||
|
@ -582,13 +605,16 @@ public class HttpExchange
|
||||||
|
|
||||||
HttpURI httpUri = new HttpURI(uri);
|
HttpURI httpUri = new HttpURI(uri);
|
||||||
String completePath = httpUri.getCompletePath();
|
String completePath = httpUri.getCompletePath();
|
||||||
setRequestURI(completePath==null ? "/" : completePath);
|
setRequestURI(completePath == null?"/":completePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified request header
|
* Adds the specified request header
|
||||||
* @param name the header name
|
*
|
||||||
* @param value the header value
|
* @param name
|
||||||
|
* the header name
|
||||||
|
* @param value
|
||||||
|
* the header value
|
||||||
*/
|
*/
|
||||||
public void addRequestHeader(String name, String value)
|
public void addRequestHeader(String name, String value)
|
||||||
{
|
{
|
||||||
|
@ -597,8 +623,11 @@ public class HttpExchange
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified request header
|
* Adds the specified request header
|
||||||
* @param name the header name
|
*
|
||||||
* @param value the header value
|
* @param name
|
||||||
|
* the header name
|
||||||
|
* @param value
|
||||||
|
* the header value
|
||||||
*/
|
*/
|
||||||
public void addRequestHeader(Buffer name, Buffer value)
|
public void addRequestHeader(Buffer name, Buffer value)
|
||||||
{
|
{
|
||||||
|
@ -607,30 +636,37 @@ public class HttpExchange
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the specified request header
|
* Sets the specified request header
|
||||||
* @param name the header name
|
*
|
||||||
* @param value the header value
|
* @param name
|
||||||
|
* the header name
|
||||||
|
* @param value
|
||||||
|
* the header value
|
||||||
*/
|
*/
|
||||||
public void setRequestHeader(String name, String value)
|
public void setRequestHeader(String name, String value)
|
||||||
{
|
{
|
||||||
getRequestFields().put(name, value);
|
getRequestFields().put(name,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the specified request header
|
* Sets the specified request header
|
||||||
* @param name the header name
|
*
|
||||||
* @param value the header value
|
* @param name
|
||||||
|
* the header name
|
||||||
|
* @param value
|
||||||
|
* the header value
|
||||||
*/
|
*/
|
||||||
public void setRequestHeader(Buffer name, Buffer value)
|
public void setRequestHeader(Buffer name, Buffer value)
|
||||||
{
|
{
|
||||||
getRequestFields().put(name, value);
|
getRequestFields().put(name,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value the content type of the request
|
* @param value
|
||||||
|
* the content type of the request
|
||||||
*/
|
*/
|
||||||
public void setRequestContentType(String value)
|
public void setRequestContentType(String value)
|
||||||
{
|
{
|
||||||
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER, value);
|
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,7 +678,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param requestContent the request content
|
* @param requestContent
|
||||||
|
* the request content
|
||||||
*/
|
*/
|
||||||
public void setRequestContent(Buffer requestContent)
|
public void setRequestContent(Buffer requestContent)
|
||||||
{
|
{
|
||||||
|
@ -650,7 +687,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param stream the request content as a stream
|
* @param stream
|
||||||
|
* the request content as a stream
|
||||||
*/
|
*/
|
||||||
public void setRequestContentSource(InputStream stream)
|
public void setRequestContentSource(InputStream stream)
|
||||||
{
|
{
|
||||||
|
@ -708,7 +746,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param retryStatus whether a retry will be attempted or not
|
* @param retryStatus
|
||||||
|
* whether a retry will be attempted or not
|
||||||
*/
|
*/
|
||||||
public void setRetryStatus(boolean retryStatus)
|
public void setRetryStatus(boolean retryStatus)
|
||||||
{
|
{
|
||||||
|
@ -716,13 +755,10 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates the cancelling of this exchange.
|
* Initiates the cancelling of this exchange. The status of the exchange is set to {@link #STATUS_CANCELLING}. Cancelling the exchange is an asynchronous
|
||||||
* The status of the exchange is set to {@link #STATUS_CANCELLING}.
|
* operation with respect to the request/response, and as such checking the request/response status of a cancelled exchange may return undefined results
|
||||||
* Cancelling the exchange is an asynchronous operation with respect to the request/response,
|
* (for example it may have only some of the response headers being sent by the server). The cancelling of the exchange is completed when the exchange
|
||||||
* and as such checking the request/response status of a cancelled exchange may return undefined results
|
* status (see {@link #getStatus()}) is {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
|
||||||
* (for example it may have only some of the response headers being sent by the server).
|
|
||||||
* The cancelling of the exchange is completed when the exchange status (see {@link #getStatus()}) is
|
|
||||||
* {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
|
|
||||||
*/
|
*/
|
||||||
public void cancel()
|
public void cancel()
|
||||||
{
|
{
|
||||||
|
@ -732,10 +768,10 @@ public class HttpExchange
|
||||||
|
|
||||||
private void done()
|
private void done()
|
||||||
{
|
{
|
||||||
synchronized(this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
disassociate();
|
disassociate();
|
||||||
_onDone=true;
|
_onDone = true;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,8 +800,8 @@ public class HttpExchange
|
||||||
|
|
||||||
void associate(HttpConnection connection)
|
void associate(HttpConnection connection)
|
||||||
{
|
{
|
||||||
if (connection.getEndPoint().getLocalHost() != null)
|
if (connection.getEndPoint().getLocalHost() != null)
|
||||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(), connection.getEndPoint().getLocalPort());
|
_localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
|
||||||
|
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
if (getStatus() == STATUS_CANCELLING)
|
if (getStatus() == STATUS_CANCELLING)
|
||||||
|
@ -789,33 +825,60 @@ public class HttpExchange
|
||||||
public static String toState(int s)
|
public static String toState(int s)
|
||||||
{
|
{
|
||||||
String state;
|
String state;
|
||||||
switch(s)
|
switch (s)
|
||||||
{
|
{
|
||||||
case STATUS_START: state="START"; break;
|
case STATUS_START:
|
||||||
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
|
state = "START";
|
||||||
case STATUS_WAITING_FOR_COMMIT: state="CONNECTED"; break;
|
break;
|
||||||
case STATUS_SENDING_REQUEST: state="SENDING"; break;
|
case STATUS_WAITING_FOR_CONNECTION:
|
||||||
case STATUS_WAITING_FOR_RESPONSE: state="WAITING"; break;
|
state = "CONNECTING";
|
||||||
case STATUS_PARSING_HEADERS: state="HEADERS"; break;
|
break;
|
||||||
case STATUS_PARSING_CONTENT: state="CONTENT"; break;
|
case STATUS_WAITING_FOR_COMMIT:
|
||||||
case STATUS_COMPLETED: state="COMPLETED"; break;
|
state = "CONNECTED";
|
||||||
case STATUS_EXPIRED: state="EXPIRED"; break;
|
break;
|
||||||
case STATUS_EXCEPTED: state="EXCEPTED"; break;
|
case STATUS_SENDING_REQUEST:
|
||||||
case STATUS_CANCELLING: state="CANCELLING"; break;
|
state = "SENDING";
|
||||||
case STATUS_CANCELLED: state="CANCELLED"; break;
|
break;
|
||||||
default: state="UNKNOWN";
|
case STATUS_WAITING_FOR_RESPONSE:
|
||||||
|
state = "WAITING";
|
||||||
|
break;
|
||||||
|
case STATUS_PARSING_HEADERS:
|
||||||
|
state = "HEADERS";
|
||||||
|
break;
|
||||||
|
case STATUS_PARSING_CONTENT:
|
||||||
|
state = "CONTENT";
|
||||||
|
break;
|
||||||
|
case STATUS_COMPLETED:
|
||||||
|
state = "COMPLETED";
|
||||||
|
break;
|
||||||
|
case STATUS_EXPIRED:
|
||||||
|
state = "EXPIRED";
|
||||||
|
break;
|
||||||
|
case STATUS_EXCEPTED:
|
||||||
|
state = "EXCEPTED";
|
||||||
|
break;
|
||||||
|
case STATUS_CANCELLING:
|
||||||
|
state = "CANCELLING";
|
||||||
|
break;
|
||||||
|
case STATUS_CANCELLED:
|
||||||
|
state = "CANCELLED";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state = "UNKNOWN";
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
String state=toState(getStatus());
|
String state=toState(getStatus());
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
long forMs = now -_lastStateChange;
|
long forMs = now -_lastStateChange;
|
||||||
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
String s= _lastState>=0
|
||||||
if (getStatus()>=STATUS_SENDING_REQUEST)
|
?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs)
|
||||||
|
:String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||||
|
if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0)
|
||||||
s+="sent="+(now-_sent)+"ms";
|
s+="sent="+(now-_sent)+"ms";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -828,79 +891,93 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when the request headers have been sent to the server.
|
* Callback called when the request headers have been sent to the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onRequestCommitted() throws IOException
|
protected void onRequestCommitted() throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when the request and its body have been sent to the server.
|
* Callback called when the request and its body have been sent to the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onRequestComplete() throws IOException
|
protected void onRequestComplete() throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when a response status line has been received from the server.
|
* Callback called when a response status line has been received from the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @param version the HTTP version
|
* @param version
|
||||||
* @param status the HTTP status code
|
* the HTTP version
|
||||||
* @param reason the HTTP status reason string
|
* @param status
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* the HTTP status code
|
||||||
|
* @param reason
|
||||||
|
* the HTTP status reason string
|
||||||
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called for each response header received from the server.
|
* Callback called for each response header received from the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @param name the header name
|
* @param name
|
||||||
* @param value the header value
|
* the header name
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @param value
|
||||||
|
* the header value
|
||||||
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when the response headers have been completely received from the server.
|
* Callback called when the response headers have been completely received from the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onResponseHeaderComplete() throws IOException
|
protected void onResponseHeaderComplete() throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called for each chunk of the response content received from the server.
|
* Callback called for each chunk of the response content received from the server. This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @param content the buffer holding the content chunk
|
* @param content
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* the buffer holding the content chunk
|
||||||
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onResponseContent(Buffer content) throws IOException
|
protected void onResponseContent(Buffer content) throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when the entire response has been received from the server
|
* Callback called when the entire response has been received from the server This implementation does nothing.
|
||||||
* This implementation does nothing.
|
*
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onResponseComplete() throws IOException
|
protected void onResponseComplete() throws IOException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when an exception was thrown during an attempt to establish the connection
|
* Callback called when an exception was thrown during an attempt to establish the connection with the server (for example the server is not listening).
|
||||||
* with the server (for example the server is not listening).
|
|
||||||
* This implementation logs a warning.
|
* This implementation logs a warning.
|
||||||
* @param x the exception thrown attempting to establish the connection with the server
|
*
|
||||||
|
* @param x
|
||||||
|
* the exception thrown attempting to establish the connection with the server
|
||||||
*/
|
*/
|
||||||
protected void onConnectionFailed(Throwable x)
|
protected void onConnectionFailed(Throwable x)
|
||||||
{
|
{
|
||||||
|
@ -908,9 +985,10 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when any other exception occurs during the handling of this exchange.
|
* Callback called when any other exception occurs during the handling of this exchange. This implementation logs a warning.
|
||||||
* This implementation logs a warning.
|
*
|
||||||
* @param x the exception thrown during the handling of this exchange
|
* @param x
|
||||||
|
* the exception thrown during the handling of this exchange
|
||||||
*/
|
*/
|
||||||
protected void onException(Throwable x)
|
protected void onException(Throwable x)
|
||||||
{
|
{
|
||||||
|
@ -918,8 +996,7 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when no response has been received within the timeout.
|
* Callback called when no response has been received within the timeout. This implementation logs a warning.
|
||||||
* This implementation logs a warning.
|
|
||||||
*/
|
*/
|
||||||
protected void onExpire()
|
protected void onExpire()
|
||||||
{
|
{
|
||||||
|
@ -927,9 +1004,10 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called when the request is retried (due to failures or authentication).
|
* Callback called when the request is retried (due to failures or authentication). Implementations must reset any consumable content that needs to be sent.
|
||||||
* Implementations must reset any consumable content that needs to be sent.
|
*
|
||||||
* @throws IOException allowed to be thrown by overriding code
|
* @throws IOException
|
||||||
|
* allowed to be thrown by overriding code
|
||||||
*/
|
*/
|
||||||
protected void onRetry() throws IOException
|
protected void onRetry() throws IOException
|
||||||
{
|
{
|
||||||
|
@ -948,8 +1026,7 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the exchange should have listeners configured for it by the destination,
|
* @return true if the exchange should have listeners configured for it by the destination, false if this is being managed elsewhere
|
||||||
* false if this is being managed elsewhere
|
|
||||||
* @see #setConfigureListeners(boolean)
|
* @see #setConfigureListeners(boolean)
|
||||||
*/
|
*/
|
||||||
public boolean configureListeners()
|
public boolean configureListeners()
|
||||||
|
@ -958,7 +1035,8 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param autoConfigure whether the listeners are configured by the destination or elsewhere
|
* @param autoConfigure
|
||||||
|
* whether the listeners are configured by the destination or elsewhere
|
||||||
*/
|
*/
|
||||||
public void setConfigureListeners(boolean autoConfigure)
|
public void setConfigureListeners(boolean autoConfigure)
|
||||||
{
|
{
|
||||||
|
@ -981,7 +1059,7 @@ public class HttpExchange
|
||||||
HttpClient httpClient = destination.getHttpClient();
|
HttpClient httpClient = destination.getHttpClient();
|
||||||
long timeout = getTimeout();
|
long timeout = getTimeout();
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
httpClient.schedule(_timeoutTask, timeout);
|
httpClient.schedule(_timeoutTask,timeout);
|
||||||
else
|
else
|
||||||
httpClient.schedule(_timeoutTask);
|
httpClient.schedule(_timeoutTask);
|
||||||
}
|
}
|
||||||
|
@ -1045,7 +1123,7 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
synchronized(HttpExchange.this)
|
synchronized (HttpExchange.this)
|
||||||
{
|
{
|
||||||
_onRequestCompleteDone = true;
|
_onRequestCompleteDone = true;
|
||||||
// Member _onDone may already be true, for example
|
// Member _onDone may already be true, for example
|
||||||
|
@ -1066,7 +1144,7 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
synchronized(HttpExchange.this)
|
synchronized (HttpExchange.this)
|
||||||
{
|
{
|
||||||
_onResponseCompleteDone = true;
|
_onResponseCompleteDone = true;
|
||||||
// Member _onDone may already be true, for example
|
// Member _onDone may already be true, for example
|
||||||
|
@ -1101,7 +1179,7 @@ public class HttpExchange
|
||||||
|
|
||||||
public void onRetry()
|
public void onRetry()
|
||||||
{
|
{
|
||||||
HttpExchange.this.setRetryStatus( true );
|
HttpExchange.this.setRetryStatus(true);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpExchange.this.onRetry();
|
HttpExchange.this.onRetry();
|
||||||
|
|
|
@ -110,25 +110,49 @@ public class RedirectListener extends HttpEventListenerWrapper
|
||||||
if (_location != null)
|
if (_location != null)
|
||||||
{
|
{
|
||||||
if (_location.indexOf("://")>0)
|
if (_location.indexOf("://")>0)
|
||||||
|
{
|
||||||
_exchange.setURL(_location);
|
_exchange.setURL(_location);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_exchange.setRequestURI(_location);
|
_exchange.setRequestURI(_location);
|
||||||
|
}
|
||||||
|
|
||||||
// destination may have changed
|
// destination may have changed
|
||||||
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme())));
|
boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme()));
|
||||||
|
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),isHttps);
|
||||||
|
|
||||||
if (_destination==destination)
|
if (_destination==destination)
|
||||||
|
{
|
||||||
_destination.resend(_exchange);
|
_destination.resend(_exchange);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// unwrap to find ultimate listener.
|
// unwrap to find ultimate listener.
|
||||||
HttpEventListener listener=this;
|
HttpEventListener listener=this;
|
||||||
while(listener instanceof HttpEventListenerWrapper)
|
while(listener instanceof HttpEventListenerWrapper)
|
||||||
|
{
|
||||||
listener=((HttpEventListenerWrapper)listener).getEventListener();
|
listener=((HttpEventListenerWrapper)listener).getEventListener();
|
||||||
|
}
|
||||||
|
|
||||||
//reset the listener
|
//reset the listener
|
||||||
_exchange.getEventListener().onRetry();
|
_exchange.getEventListener().onRetry();
|
||||||
_exchange.reset();
|
_exchange.reset();
|
||||||
_exchange.setEventListener(listener);
|
_exchange.setEventListener(listener);
|
||||||
|
|
||||||
|
// Set the new Host header
|
||||||
|
Address address = _exchange.getAddress();
|
||||||
|
int port = address.getPort();
|
||||||
|
StringBuilder hostHeader = new StringBuilder( 64 );
|
||||||
|
hostHeader.append( address.getHost() );
|
||||||
|
if( !( ( port == 80 && !isHttps ) || ( port == 443 && isHttps ) ) )
|
||||||
|
{
|
||||||
|
hostHeader.append( ':' );
|
||||||
|
hostHeader.append( port );
|
||||||
|
}
|
||||||
|
|
||||||
|
_exchange.setRequestHeader( HttpHeaders.HOST, hostHeader.toString() );
|
||||||
|
|
||||||
destination.send(_exchange);
|
destination.send(_exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,5 +180,28 @@ public class RedirectListener extends HttpEventListenerWrapper
|
||||||
|
|
||||||
super.onRetry();
|
super.onRetry();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate failed connection
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed( Throwable ex )
|
||||||
|
{
|
||||||
|
setDelegatingRequests(true);
|
||||||
|
setDelegatingResponses(true);
|
||||||
|
|
||||||
|
super.onConnectionFailed( ex );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate onException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onException( Throwable ex )
|
||||||
|
{
|
||||||
|
setDelegatingRequests(true);
|
||||||
|
setDelegatingResponses(true);
|
||||||
|
|
||||||
|
super.onException( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,10 +15,13 @@ package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.UnresolvedAddressException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
|
@ -48,7 +51,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||||
private final HttpClient _httpClient;
|
private final HttpClient _httpClient;
|
||||||
private final Manager _selectorManager=new Manager();
|
private final Manager _selectorManager=new Manager();
|
||||||
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
||||||
private SSLContext _sslContext;
|
|
||||||
private Buffers _sslBuffers;
|
private Buffers _sslBuffers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,31 +91,34 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||||
public void startConnection( HttpDestination destination )
|
public void startConnection( HttpDestination destination )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
SocketChannel channel = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SocketChannel channel = SocketChannel.open();
|
channel = SocketChannel.open();
|
||||||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||||
channel.socket().setTcpNoDelay(true);
|
channel.socket().setTcpNoDelay(true);
|
||||||
|
|
||||||
if (_httpClient.isConnectBlocking())
|
if (_httpClient.isConnectBlocking())
|
||||||
{
|
{
|
||||||
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||||
channel.configureBlocking(false);
|
channel.configureBlocking(false);
|
||||||
_selectorManager.register( channel, destination );
|
_selectorManager.register( channel, destination );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
channel.configureBlocking( false );
|
channel.configureBlocking(false);
|
||||||
channel.connect(address.toSocketAddress());
|
channel.connect(address.toSocketAddress());
|
||||||
_selectorManager.register( channel, destination );
|
_selectorManager.register(channel,destination);
|
||||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
|
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
|
||||||
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
|
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
|
||||||
_connectingChannels.put(channel, connectTimeout);
|
_connectingChannels.put(channel,connectTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(IOException ex)
|
catch(IOException ex)
|
||||||
{
|
{
|
||||||
|
if (channel != null)
|
||||||
|
channel.close();
|
||||||
destination.onConnectionFailed(ex);
|
destination.onConnectionFailed(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,19 +199,16 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||||
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
|
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
|
||||||
{
|
{
|
||||||
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
|
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
|
||||||
if (_sslContext == null)
|
|
||||||
_sslContext = sslContextFactory.getSslContext();
|
|
||||||
|
|
||||||
SSLEngine sslEngine;
|
SSLEngine sslEngine;
|
||||||
if (channel != null && sslContextFactory.isSessionCachingEnabled())
|
if (channel != null)
|
||||||
{
|
{
|
||||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||||
int peerPort = channel.socket().getPort();
|
int peerPort = channel.socket().getPort();
|
||||||
sslEngine = _sslContext.createSSLEngine(peerHost, peerPort);
|
sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sslEngine = _sslContext.createSSLEngine();
|
sslEngine = sslContextFactory.newSslEngine();
|
||||||
}
|
}
|
||||||
sslEngine.setUseClientMode(true);
|
sslEngine.setUseClientMode(true);
|
||||||
sslEngine.beginHandshake();
|
sslEngine.beginHandshake();
|
||||||
|
|
|
@ -45,18 +45,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||||
|
|
||||||
public void startConnection(final HttpDestination destination) throws IOException
|
public void startConnection(final HttpDestination destination) throws IOException
|
||||||
{
|
{
|
||||||
Socket socket=null;
|
Socket socket= destination.isSecure()
|
||||||
|
?_httpClient.getSslContextFactory().newSslSocket()
|
||||||
if ( destination.isSecure() )
|
:SocketFactory.getDefault().createSocket();
|
||||||
{
|
|
||||||
SSLContext sslContext = _httpClient.getSSLContext();
|
|
||||||
socket = sslContext.getSocketFactory().createSocket();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG.debug("Using Regular Socket");
|
|
||||||
socket = SocketFactory.getDefault().createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.setSoTimeout(0);
|
socket.setSoTimeout(0);
|
||||||
socket.setTcpNoDelay(true);
|
socket.setTcpNoDelay(true);
|
||||||
|
@ -97,6 +88,17 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
||||||
destination.onException(e);
|
destination.onException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
destination.returnConnection(connection,true);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOG.debug(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
|
@ -34,7 +32,6 @@ import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
import org.eclipse.jetty.util.log.StdErrLog;
|
import org.eclipse.jetty.util.log.StdErrLog;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -45,8 +42,6 @@ import org.junit.Test;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractHttpExchangeCancelTest
|
public abstract class AbstractHttpExchangeCancelTest
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(AbstractHttpExchangeCancelTest.class);
|
|
||||||
|
|
||||||
private Server server;
|
private Server server;
|
||||||
private Connector connector;
|
private Connector connector;
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,31 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
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
|
public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||||
{
|
{
|
||||||
@Override
|
private static ServerAndClientCreator serverAndClientCreator = new AsyncSslServerAndClientCreator();
|
||||||
public void setUp() throws Exception
|
|
||||||
|
@Before
|
||||||
|
public void setUpOnce() throws Exception
|
||||||
{
|
{
|
||||||
_scheme="https";
|
_scheme="https";
|
||||||
startServer();
|
_server = serverAndClientCreator.createServer();
|
||||||
_httpClient=new HttpClient();
|
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||||
_httpClient.setIdleTimeout(2000);
|
_port = _server.getConnectors()[0].getLocalPort();
|
||||||
_httpClient.setTimeout(2500);
|
|
||||||
_httpClient.setConnectTimeout(1000);
|
|
||||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
|
||||||
_httpClient.setMaxConnectionsPerAddress(2);
|
|
||||||
_httpClient.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPerf1() throws Exception
|
||||||
|
{
|
||||||
|
sender(10,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,28 +13,23 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
|
||||||
|
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||||
{
|
{
|
||||||
@Override
|
private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
|
||||||
public void setUp() throws Exception
|
|
||||||
|
@Before
|
||||||
|
public void setUpOnce() throws Exception
|
||||||
{
|
{
|
||||||
_scheme = "https";
|
_scheme="https";
|
||||||
startServer();
|
_server = serverAndClientCreator.createServer();
|
||||||
_httpClient = new HttpClient();
|
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
_port = _server.getConnectors()[0].getLocalPort();
|
||||||
_httpClient.setMaxConnectionsPerAddress(2);
|
|
||||||
|
|
||||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
|
||||||
|
|
||||||
_httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
|
||||||
_httpClient.setKeyStorePassword("storepwd");
|
|
||||||
_httpClient.setKeyManagerPassword("keypwd");
|
|
||||||
_httpClient.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
public final class HttpAsserts
|
||||||
|
{
|
||||||
|
public static void assertContainsHeaderKey(String expectedKey, HttpFields headers)
|
||||||
|
{
|
||||||
|
if (headers.containsKey(expectedKey))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> names = Collections.list(headers.getFieldNames());
|
||||||
|
StringBuilder err = new StringBuilder();
|
||||||
|
err.append("Missing expected header key [").append(expectedKey);
|
||||||
|
err.append("] (of ").append(names.size()).append(" header fields)");
|
||||||
|
for (int i = 0; i < names.size(); i++)
|
||||||
|
{
|
||||||
|
String value = headers.getStringField(names.get(i));
|
||||||
|
err.append("\n").append(i).append("] ").append(names.get(i));
|
||||||
|
err.append(": ").append(value);
|
||||||
|
}
|
||||||
|
Assert.fail(err.toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,14 +13,9 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.matchers.JUnitMatchers.*;
|
||||||
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.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -30,13 +25,10 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import org.eclipse.jetty.client.helperClasses.HttpServerAndClientCreator;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.client.security.ProxyAuthorization;
|
import org.eclipse.jetty.client.security.ProxyAuthorization;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeaders;
|
|
||||||
import org.eclipse.jetty.http.HttpMethods;
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.io.Buffer;
|
import org.eclipse.jetty.io.Buffer;
|
||||||
|
@ -44,17 +36,13 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||||
import org.eclipse.jetty.io.Connection;
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EofException;
|
import org.eclipse.jetty.io.EofException;
|
||||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||||
import org.eclipse.jetty.server.Connector;
|
|
||||||
import org.eclipse.jetty.server.Request;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
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.Stress;
|
import org.eclipse.jetty.toolchain.test.Stress;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -63,37 +51,44 @@ import org.junit.Test;
|
||||||
*/
|
*/
|
||||||
public class HttpExchangeTest
|
public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HttpExchangeTest.class);
|
final static boolean verbose=false;
|
||||||
|
protected static int _maxConnectionsPerAddress = 2;
|
||||||
protected int _maxConnectionsPerAddress = 2;
|
protected static String _scheme = "http";
|
||||||
protected String _scheme = "http";
|
protected static Server _server;
|
||||||
protected Server _server;
|
protected static int _port;
|
||||||
protected int _port;
|
protected static HttpClient _httpClient;
|
||||||
protected HttpClient _httpClient;
|
protected static AtomicInteger _count = new AtomicInteger();
|
||||||
protected Connector _connector;
|
protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
|
||||||
protected AtomicInteger _count = new AtomicInteger();
|
|
||||||
|
protected static URI getBaseURI()
|
||||||
|
{
|
||||||
|
return URI.create(_scheme + "://localhost:" + _port + "/");
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
// TODO work out why BeforeClass does not work here?
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception
|
public void setUpOnce() throws Exception
|
||||||
{
|
{
|
||||||
startServer();
|
_scheme = "http";
|
||||||
_httpClient=new HttpClient();
|
_server = serverAndClientCreator.createServer();
|
||||||
_httpClient.setIdleTimeout(3000);
|
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||||
_httpClient.setTimeout(3500);
|
_port = _server.getConnectors()[0].getLocalPort();
|
||||||
_httpClient.setConnectTimeout(2000);
|
|
||||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
|
||||||
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
|
|
||||||
_httpClient.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception
|
public void tearDownOnce() throws Exception
|
||||||
{
|
{
|
||||||
_httpClient.stop();
|
_httpClient.stop();
|
||||||
Thread.sleep(500);
|
long startTime = System.currentTimeMillis();
|
||||||
stopServer();
|
while (!_httpClient.getState().equals(AbstractLifeCycle.STOPPED))
|
||||||
|
{
|
||||||
|
if (System.currentTimeMillis() - startTime > 1000)
|
||||||
|
break;
|
||||||
|
Thread.sleep(5);
|
||||||
|
}
|
||||||
|
_server.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -110,7 +105,9 @@ public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
sender(1,false);
|
sender(1,false);
|
||||||
sender(1,true);
|
sender(1,true);
|
||||||
|
sender(10,false);
|
||||||
|
sender(10,true);
|
||||||
|
|
||||||
if (Stress.isEnabled())
|
if (Stress.isEnabled())
|
||||||
{
|
{
|
||||||
sender(100,false);
|
sender(100,false);
|
||||||
|
@ -118,67 +115,72 @@ public class HttpExchangeTest
|
||||||
sender(10000,false);
|
sender(10000,false);
|
||||||
sender(10000,true);
|
sender(10000,true);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
sender(10,false);
|
|
||||||
sender(10,true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Test sending data through the exchange.
|
* Test sending data through the exchange.
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void sender(final int nb,final boolean close) throws Exception
|
public void sender(final int nb, final boolean close) throws Exception
|
||||||
{
|
{
|
||||||
_count.set(0);
|
_count.set(0);
|
||||||
final CountDownLatch complete=new CountDownLatch(nb);
|
final CountDownLatch complete = new CountDownLatch(nb);
|
||||||
final CountDownLatch latch=new CountDownLatch(nb);
|
final AtomicInteger allcontent = new AtomicInteger(nb);
|
||||||
HttpExchange[] httpExchange = new HttpExchange[nb];
|
HttpExchange[] httpExchange = new HttpExchange[nb];
|
||||||
long start=System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
for (int i=0; i<nb; i++)
|
for (int i = 0; i < nb; i++)
|
||||||
{
|
{
|
||||||
final int n=i;
|
final int n = i;
|
||||||
|
|
||||||
httpExchange[n]=new HttpExchange()
|
httpExchange[n] = new HttpExchange()
|
||||||
{
|
{
|
||||||
String result="pending";
|
String result = "pending";
|
||||||
int len=0;
|
int len = 0;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void onRequestCommitted()
|
protected void onRequestCommitted()
|
||||||
{
|
{
|
||||||
result="committed";
|
if (verbose)
|
||||||
|
System.err.println("[ ");
|
||||||
|
result = "committed";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void onRequestComplete() throws IOException
|
protected void onRequestComplete() throws IOException
|
||||||
{
|
{
|
||||||
result="sent";
|
if (verbose)
|
||||||
|
System.err.println("[ ==");
|
||||||
|
result = "sent";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected void onResponseStatus(Buffer version, int status, Buffer reason)
|
protected void onResponseStatus(Buffer version, int status, Buffer reason)
|
||||||
{
|
{
|
||||||
result="status";
|
if (verbose)
|
||||||
|
System.err.println("] "+version+" "+status+" "+reason);
|
||||||
|
result = "status";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void onResponseHeader(Buffer name, Buffer value)
|
protected void onResponseHeader(Buffer name, Buffer value)
|
||||||
{
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+name+": "+value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void onResponseHeaderComplete() throws IOException
|
protected void onResponseHeaderComplete() throws IOException
|
||||||
{
|
{
|
||||||
result="content";
|
if (verbose)
|
||||||
|
System.err.println("] -");
|
||||||
|
result = "content";
|
||||||
super.onResponseHeaderComplete();
|
super.onResponseHeaderComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,20 +188,22 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
protected void onResponseContent(Buffer content)
|
protected void onResponseContent(Buffer content)
|
||||||
{
|
{
|
||||||
len+=content.length();
|
len += content.length();
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+content.length()+" -> "+len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
protected void onResponseComplete()
|
protected void onResponseComplete()
|
||||||
{
|
{
|
||||||
result="complete";
|
if (verbose)
|
||||||
if (len==2009)
|
System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
|
||||||
latch.countDown();
|
result = "complete";
|
||||||
|
if (len == 2009)
|
||||||
|
allcontent.decrementAndGet();
|
||||||
else
|
else
|
||||||
{
|
System.err.println(n + " ONLY " + len+ "/2009");
|
||||||
System.err.println(n+" ONLY "+len);
|
|
||||||
}
|
|
||||||
complete.countDown();
|
complete.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +211,11 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
protected void onConnectionFailed(Throwable ex)
|
protected void onConnectionFailed(Throwable ex)
|
||||||
{
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+ex);
|
||||||
complete.countDown();
|
complete.countDown();
|
||||||
result="failed";
|
result = "failed";
|
||||||
System.err.println(n+" FAILED "+ex);
|
System.err.println(n + " FAILED " + ex);
|
||||||
super.onConnectionFailed(ex);
|
super.onConnectionFailed(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,9 +223,11 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
protected void onException(Throwable ex)
|
protected void onException(Throwable ex)
|
||||||
{
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+ex);
|
||||||
complete.countDown();
|
complete.countDown();
|
||||||
result="excepted";
|
result = "excepted";
|
||||||
System.err.println(n+" EXCEPTED "+ex);
|
System.err.println(n + " EXCEPTED " + ex);
|
||||||
super.onException(ex);
|
super.onException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,9 +235,11 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
protected void onExpire()
|
protected void onExpire()
|
||||||
{
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] expired");
|
||||||
complete.countDown();
|
complete.countDown();
|
||||||
result="expired";
|
result = "expired";
|
||||||
System.err.println(n+" EXPIRED "+len);
|
System.err.println(n + " EXPIRED " + len);
|
||||||
super.onExpire();
|
super.onExpire();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,29 +247,24 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return n+" "+result+" "+len;
|
return n+"/"+result+"/"+len+"/"+super.toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
httpExchange[n].setURL(_scheme+"://localhost:"+_port+"/"+n);
|
httpExchange[n].setURI(getBaseURI().resolve("/" + n));
|
||||||
httpExchange[n].addRequestHeader("arbitrary","value");
|
httpExchange[n].addRequestHeader("arbitrary","value");
|
||||||
if (close)
|
if (close)
|
||||||
httpExchange[n].setRequestHeader("Connection","close");
|
httpExchange[n].setRequestHeader("Connection","close");
|
||||||
|
|
||||||
_httpClient.send(httpExchange[n]);
|
_httpClient.send(httpExchange[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(complete.await(45,TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
long elapsed=System.currentTimeMillis()-start;
|
|
||||||
|
|
||||||
// make windows-friendly ... System.currentTimeMillis() on windows is dope!
|
if (!complete.await(2,TimeUnit.SECONDS))
|
||||||
/*
|
System.err.println(_httpClient.dump());
|
||||||
if(elapsed>0)
|
|
||||||
System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
|
|
||||||
*/
|
|
||||||
|
|
||||||
assertEquals("nb="+nb+" close="+close,0,latch.getCount());
|
assertTrue(complete.await(20,TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
assertEquals("nb="+nb+" close="+close,0,allcontent.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -269,7 +274,7 @@ public class HttpExchangeTest
|
||||||
for (int i=0;i<20;i++)
|
for (int i=0;i<20;i++)
|
||||||
{
|
{
|
||||||
ContentExchange httpExchange=new ContentExchange();
|
ContentExchange httpExchange=new ContentExchange();
|
||||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, null, null, null));
|
httpExchange.setURI(getBaseURI());
|
||||||
httpExchange.setMethod(HttpMethods.POST);
|
httpExchange.setMethod(HttpMethods.POST);
|
||||||
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
|
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
|
@ -288,12 +293,14 @@ public class HttpExchangeTest
|
||||||
for (int i=0;i<10;i++)
|
for (int i=0;i<10;i++)
|
||||||
{
|
{
|
||||||
ContentExchange httpExchange=new ContentExchange();
|
ContentExchange httpExchange=new ContentExchange();
|
||||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, "/", "i="+i, null));
|
URI uri = getBaseURI().resolve("?i=" + i);
|
||||||
|
httpExchange.setURI(uri);
|
||||||
httpExchange.setMethod(HttpMethods.GET);
|
httpExchange.setMethod(HttpMethods.GET);
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
int status = httpExchange.waitForDone();
|
int status = httpExchange.waitForDone();
|
||||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||||
String result=httpExchange.getResponseContent();
|
String result=httpExchange.getResponseContent();
|
||||||
|
assertNotNull("Should have received response content", result);
|
||||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||||
|
@ -308,17 +315,16 @@ public class HttpExchangeTest
|
||||||
for (int i=0;i<10;i++)
|
for (int i=0;i<10;i++)
|
||||||
{
|
{
|
||||||
ContentExchange httpExchange=new ContentExchange();
|
ContentExchange httpExchange=new ContentExchange();
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
URI uri = getBaseURI().resolve("?i=" + i);
|
||||||
|
httpExchange.setURI(uri);
|
||||||
httpExchange.setMethod(HttpMethods.GET);
|
httpExchange.setMethod(HttpMethods.GET);
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
int status = httpExchange.waitForDone();
|
int status = httpExchange.waitForDone();
|
||||||
|
|
||||||
assertNotNull(httpExchange.getLocalAddress());
|
assertNotNull(httpExchange.getLocalAddress());
|
||||||
|
|
||||||
//System.out.println("Local Address: " + httpExchange.getLocalAddress());
|
|
||||||
|
|
||||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
|
||||||
String result=httpExchange.getResponseContent();
|
String result=httpExchange.getResponseContent();
|
||||||
|
assertNotNull("Should have received response content", result);
|
||||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||||
|
@ -355,7 +361,7 @@ public class HttpExchangeTest
|
||||||
throwable.set(x);
|
throwable.set(x);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
httpExchange.setURI(getBaseURI());
|
||||||
httpExchange.setMethod("SLEEP");
|
httpExchange.setMethod("SLEEP");
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
new Thread()
|
new Thread()
|
||||||
|
@ -374,6 +380,7 @@ public class HttpExchangeTest
|
||||||
System.err.println(throwable.get());
|
System.err.println(throwable.get());
|
||||||
assertTrue(throwable.get().toString().indexOf("close")>=0);
|
assertTrue(throwable.get().toString().indexOf("close")>=0);
|
||||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||||
|
_httpClient.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -381,7 +388,54 @@ public class HttpExchangeTest
|
||||||
public void testBigPostWithContentExchange() throws Exception
|
public void testBigPostWithContentExchange() throws Exception
|
||||||
{
|
{
|
||||||
int size =32;
|
int size =32;
|
||||||
ContentExchange httpExchange=new ContentExchange();
|
ContentExchange httpExchange=new ContentExchange()
|
||||||
|
{
|
||||||
|
int total;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+version+" "+status+" "+reason);
|
||||||
|
super.onResponseStatus(version,status,reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] "+name+": "+value);
|
||||||
|
super.onResponseHeader(name,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void onResponseContent(Buffer content) throws IOException
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
total+=content.length();
|
||||||
|
System.err.println("] "+content.length()+" -> "+total);
|
||||||
|
}
|
||||||
|
super.onResponseContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRequestComplete() throws IOException
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] ==");
|
||||||
|
super.onRequestComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResponseHeaderComplete() throws IOException
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
System.err.println("] --");
|
||||||
|
super.onResponseHeaderComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
Buffer babuf = new ByteArrayBuffer(size*36*1024);
|
Buffer babuf = new ByteArrayBuffer(size*36*1024);
|
||||||
Buffer niobuf = new DirectNIOBuffer(size*36*1024);
|
Buffer niobuf = new DirectNIOBuffer(size*36*1024);
|
||||||
|
@ -394,28 +448,27 @@ public class HttpExchangeTest
|
||||||
niobuf.put(bytes);
|
niobuf.put(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
httpExchange.setURI(getBaseURI());
|
||||||
httpExchange.setMethod(HttpMethods.POST);
|
httpExchange.setMethod(HttpMethods.POST);
|
||||||
httpExchange.setRequestContentType("application/data");
|
httpExchange.setRequestContentType("application/data");
|
||||||
httpExchange.setRequestContent(babuf);
|
httpExchange.setRequestContent(babuf);
|
||||||
|
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
int status = httpExchange.waitForDone();
|
int status = httpExchange.waitForDone();
|
||||||
|
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||||
String result=httpExchange.getResponseContent();
|
String result=httpExchange.getResponseContent();
|
||||||
assertEquals(babuf.length(),result.length());
|
assertEquals(babuf.length(),result.length());
|
||||||
|
|
||||||
httpExchange.reset();
|
httpExchange.reset();
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
httpExchange.setURI(getBaseURI());
|
||||||
httpExchange.setMethod(HttpMethods.POST);
|
httpExchange.setMethod(HttpMethods.POST);
|
||||||
httpExchange.setRequestContentType("application/data");
|
httpExchange.setRequestContentType("application/data");
|
||||||
httpExchange.setRequestContent(niobuf);
|
httpExchange.setRequestContent(niobuf);
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
status = httpExchange.waitForDone();
|
status = httpExchange.waitForDone();
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||||
result=httpExchange.getResponseContent();
|
result=httpExchange.getResponseContent();
|
||||||
assertEquals(niobuf.length(),result.length());
|
assertEquals(niobuf.length(),result.length());
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -426,7 +479,7 @@ public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port);
|
httpExchange.setURI(getBaseURI());
|
||||||
httpExchange.setMethod(HttpMethods.POST);
|
httpExchange.setMethod(HttpMethods.POST);
|
||||||
|
|
||||||
final String data="012345678901234567890123456789012345678901234567890123456789";
|
final String data="012345678901234567890123456789012345678901234567890123456789";
|
||||||
|
@ -447,7 +500,7 @@ public class HttpExchangeTest
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] b, int off, int len) throws IOException
|
public int read(byte[] b, int off, int len) throws IOException
|
||||||
{
|
{
|
||||||
if (_index>=data.length())
|
if (_index >= data.length())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -458,28 +511,28 @@ public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
int l=0;
|
|
||||||
|
|
||||||
while (l<5 && _index<data.length() && l<len)
|
int l = 0;
|
||||||
b[off+l++]=(byte)data.charAt(_index++);
|
|
||||||
|
while (l < 5 && _index < data.length() && l < len)
|
||||||
|
b[off + l++] = (byte)data.charAt(_index++);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
httpExchange.setRequestContentSource(content);
|
httpExchange.setRequestContentSource(content);
|
||||||
//httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
// httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
||||||
|
|
||||||
_httpClient.send(httpExchange);
|
_httpClient.send(httpExchange);
|
||||||
|
|
||||||
int status = httpExchange.waitForDone();
|
int status = httpExchange.waitForDone();
|
||||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
// httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||||
String result=httpExchange.getResponseContent();
|
String result = httpExchange.getResponseContent();
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||||
assertEquals(data,result);
|
assertEquals(data,result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Test
|
@Test
|
||||||
public void testProxy() throws Exception
|
public void testProxy() throws Exception
|
||||||
|
@ -499,6 +552,7 @@ public class HttpExchangeTest
|
||||||
int status = httpExchange.waitForDone();
|
int status = httpExchange.waitForDone();
|
||||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||||
String result=httpExchange.getResponseContent();
|
String result=httpExchange.getResponseContent();
|
||||||
|
assertNotNull("Should have received response content", result);
|
||||||
result=result.trim();
|
result=result.trim();
|
||||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||||
assertTrue(result.startsWith("Proxy request: http://jetty.eclipse.org:8080/jetty-6"));
|
assertTrue(result.startsWith("Proxy request: http://jetty.eclipse.org:8080/jetty-6"));
|
||||||
|
@ -515,36 +569,42 @@ public class HttpExchangeTest
|
||||||
@Test
|
@Test
|
||||||
public void testReserveConnections () throws Exception
|
public void testReserveConnections () throws Exception
|
||||||
{
|
{
|
||||||
final HttpDestination destination = _httpClient.getDestination (new Address("localhost", _port), _scheme.equalsIgnoreCase("https"));
|
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||||
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
final HttpDestination destination = _httpClient.getDestination(new Address("localhost",_port),_scheme.equalsIgnoreCase("https"));
|
||||||
for (int i=0; i < _maxConnectionsPerAddress; i++)
|
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
||||||
{
|
for (int i = 0; i < _maxConnectionsPerAddress; i++)
|
||||||
connections[i] = destination.reserveConnection(200);
|
{
|
||||||
assertNotNull(connections[i]);
|
connections[i] = destination.reserveConnection(200);
|
||||||
HttpExchange ex = new ContentExchange();
|
assertNotNull(connections[i]);
|
||||||
ex.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
HttpExchange ex = new ContentExchange();
|
||||||
ex.setMethod(HttpMethods.GET);
|
ex.setURI(getBaseURI().resolve("?i=" + i));
|
||||||
connections[i].send(ex);
|
ex.setMethod(HttpMethods.GET);
|
||||||
}
|
connections[i].send(ex);
|
||||||
|
}
|
||||||
|
|
||||||
//try to get a connection, and only wait 500ms, as we have
|
// try to get a connection, and only wait 500ms, as we have
|
||||||
//already reserved the max, should return null
|
// already reserved the max, should return null
|
||||||
Connection c = destination.reserveConnection(500);
|
Connection c = destination.reserveConnection(500);
|
||||||
assertNull(c);
|
assertNull(c);
|
||||||
|
|
||||||
//unreserve first connection
|
// unreserve first connection
|
||||||
destination.returnConnection(connections[0], false);
|
destination.returnConnection(connections[0],false);
|
||||||
|
|
||||||
//reserving one should now work
|
// reserving one should now work
|
||||||
c = destination.reserveConnection(500);
|
c = destination.reserveConnection(500);
|
||||||
assertNotNull(c);
|
assertNotNull(c);
|
||||||
|
|
||||||
|
// release connections
|
||||||
|
for (HttpConnection httpConnection : connections){
|
||||||
|
destination.returnConnection(httpConnection,false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOptionsWithExchange() throws Exception
|
public void testOptionsWithExchange() throws Exception
|
||||||
{
|
{
|
||||||
ContentExchange httpExchange = new ContentExchange(true);
|
ContentExchange httpExchange = new ContentExchange(true);
|
||||||
httpExchange.setURL(_scheme+"://localhost:"+_port);
|
httpExchange.setURL(getBaseURI().toASCIIString());
|
||||||
httpExchange.setRequestURI("*");
|
httpExchange.setRequestURI("*");
|
||||||
httpExchange.setMethod(HttpMethods.OPTIONS);
|
httpExchange.setMethod(HttpMethods.OPTIONS);
|
||||||
// httpExchange.setRequestHeader("Connection","close");
|
// httpExchange.setRequestHeader("Connection","close");
|
||||||
|
@ -555,8 +615,10 @@ public class HttpExchangeTest
|
||||||
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
|
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
|
||||||
|
|
||||||
HttpFields headers = httpExchange.getResponseFields();
|
HttpFields headers = httpExchange.getResponseFields();
|
||||||
assertTrue("Response contains Allow header", headers.containsKey("Allow"));
|
HttpAsserts.assertContainsHeaderKey("Content-Length", headers);
|
||||||
|
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
||||||
|
|
||||||
|
HttpAsserts.assertContainsHeaderKey("Allow",headers);
|
||||||
String allow = headers.getStringField("Allow");
|
String allow = headers.getStringField("Allow");
|
||||||
String expectedMethods[] =
|
String expectedMethods[] =
|
||||||
{ "GET", "HEAD", "POST", "PUT", "DELETE", "MOVE", "OPTIONS", "TRACE" };
|
{ "GET", "HEAD", "POST", "PUT", "DELETE", "MOVE", "OPTIONS", "TRACE" };
|
||||||
|
@ -564,9 +626,6 @@ public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
assertThat(allow,containsString(expectedMethod));
|
assertThat(allow,containsString(expectedMethod));
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("Response contains Content-Length header", headers.containsKey("Content-Length"));
|
|
||||||
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -574,115 +633,20 @@ public class HttpExchangeTest
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] buffer=new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int len;
|
int len;
|
||||||
while ((len=in.read(buffer))>=0)
|
while ((len = in.read(buffer)) >= 0)
|
||||||
{
|
{
|
||||||
out.write(buffer,0,len);
|
out.write(buffer,0,len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EofException e)
|
catch (EofException e)
|
||||||
{
|
{
|
||||||
System.err.println("HttpExchangeTest#copyStream: "+e);
|
System.err.println("HttpExchangeTest#copyStream: " + e);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected void newServer() throws Exception
|
|
||||||
{
|
|
||||||
_server=new Server();
|
|
||||||
_server.setGracefulShutdown(500);
|
|
||||||
_connector=new SelectChannelConnector();
|
|
||||||
|
|
||||||
_connector.setMaxIdleTime(3000000);
|
|
||||||
|
|
||||||
_connector.setPort(0);
|
|
||||||
_server.setConnectors(new Connector[] { _connector });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected void startServer() throws Exception
|
|
||||||
{
|
|
||||||
newServer();
|
|
||||||
_server.setHandler(new AbstractHandler()
|
|
||||||
{
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
baseRequest.setHandled(true);
|
|
||||||
response.setStatus(200);
|
|
||||||
_count.incrementAndGet();
|
|
||||||
|
|
||||||
if (request.getServerName().equals("jetty.eclipse.org"))
|
|
||||||
{
|
|
||||||
response.getOutputStream().println("Proxy request: "+request.getRequestURL());
|
|
||||||
response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
|
|
||||||
}
|
|
||||||
else if (request.getMethod().equalsIgnoreCase("GET"))
|
|
||||||
{
|
|
||||||
response.getOutputStream().println("<hello>");
|
|
||||||
for (; i<100; i++)
|
|
||||||
{
|
|
||||||
response.getOutputStream().println(" <world>"+i+"</world");
|
|
||||||
if (i%20==0)
|
|
||||||
response.getOutputStream().flush();
|
|
||||||
}
|
|
||||||
response.getOutputStream().println("</hello>");
|
|
||||||
}
|
|
||||||
else if (request.getMethod().equalsIgnoreCase("OPTIONS"))
|
|
||||||
{
|
|
||||||
if ("*".equals(target))
|
|
||||||
{
|
|
||||||
response.setContentLength(0);
|
|
||||||
response.setHeader("Allow","GET,HEAD,POST,PUT,DELETE,MOVE,OPTIONS,TRACE");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (request.getMethod().equalsIgnoreCase("SLEEP"))
|
|
||||||
{
|
|
||||||
Thread.sleep(10000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.setContentType(request.getContentType());
|
|
||||||
int size=request.getContentLength();
|
|
||||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size>0?size:32768);
|
|
||||||
IO.copy(request.getInputStream(),bout);
|
|
||||||
response.getOutputStream().write(bout.toByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(InterruptedException e)
|
|
||||||
{
|
|
||||||
LOG.debug(e);
|
|
||||||
}
|
|
||||||
catch(IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch(Throwable e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new ServletException(e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_server.start();
|
|
||||||
_port=_connector.getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private void stopServer() throws Exception
|
|
||||||
{
|
|
||||||
_server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,67 +13,36 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.not;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||||
|
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|
||||||
import org.eclipse.jetty.toolchain.test.OS;
|
import org.eclipse.jetty.toolchain.test.OS;
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.Stress;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional testing for HttpExchange.
|
* Functional testing for HttpExchange.
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SslHttpExchangeTest extends HttpExchangeTest
|
public class SslHttpExchangeTest extends HttpExchangeTest
|
||||||
{
|
{
|
||||||
|
protected static ServerAndClientCreator serverAndClientCreator = new SslServerAndClientCreator();
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Before
|
@Before
|
||||||
@Override
|
public void setUpOnce() throws Exception
|
||||||
public void setUp() throws Exception
|
|
||||||
{
|
{
|
||||||
_scheme="https";
|
_scheme="https";
|
||||||
startServer();
|
_server = serverAndClientCreator.createServer();
|
||||||
_httpClient=new HttpClient();
|
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||||
_httpClient.setIdleTimeout(2000);
|
Connector[] connectors = _server.getConnectors();
|
||||||
_httpClient.setTimeout(2500);
|
_port = connectors[0].getLocalPort();
|
||||||
_httpClient.setConnectTimeout(1000);
|
|
||||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
|
||||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
|
||||||
_httpClient.setMaxConnectionsPerAddress(2);
|
|
||||||
_httpClient.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
|
||||||
protected void newServer()
|
|
||||||
{
|
|
||||||
_server = new Server();
|
|
||||||
//SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
|
||||||
SslSocketConnector connector = new SslSocketConnector();
|
|
||||||
|
|
||||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
|
||||||
|
|
||||||
connector.setPort(0);
|
|
||||||
SslContextFactory cf = connector.getSslContextFactory();
|
|
||||||
cf.setKeyStore(keystore);
|
|
||||||
cf.setKeyStorePassword("storepwd");
|
|
||||||
cf.setKeyManagerPassword("keypwd");
|
|
||||||
connector.setAllowRenegotiate(true);
|
|
||||||
|
|
||||||
_server.setConnectors(new Connector[]
|
|
||||||
{ connector });
|
|
||||||
_connector=connector;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void IgnoreTestOnBuggyIBM()
|
private void IgnoreTestOnBuggyIBM()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 2009-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.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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(AbstractSslServerAndClientCreator.class);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public Server createServer() throws Exception
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
//SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||||
|
SslSocketConnector connector = new SslSocketConnector();
|
||||||
|
|
||||||
|
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||||
|
|
||||||
|
connector.setPort(0);
|
||||||
|
SslContextFactory cf = connector.getSslContextFactory();
|
||||||
|
cf.setKeyStore(keystore);
|
||||||
|
cf.setKeyStorePassword("storepwd");
|
||||||
|
cf.setKeyManagerPassword("keypwd");
|
||||||
|
connector.setAllowRenegotiate(true);
|
||||||
|
|
||||||
|
server.setConnectors(new Connector[]{ connector });
|
||||||
|
server.setHandler(new GenericServerHandler());
|
||||||
|
server.start();
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
|
||||||
|
public class AsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||||
|
{
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||||
|
{
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||||
|
httpClient.setMaxConnectionsPerAddress(2);
|
||||||
|
|
||||||
|
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||||
|
httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||||
|
httpClient.setKeyStorePassword("storepwd");
|
||||||
|
httpClient.setKeyManagerPassword("keypwd");
|
||||||
|
httpClient.start();
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
|
||||||
|
public class ExternalKeyStoreAsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||||
|
{
|
||||||
|
|
||||||
|
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||||
|
{
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||||
|
httpClient.setMaxConnectionsPerAddress(2);
|
||||||
|
|
||||||
|
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||||
|
|
||||||
|
httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||||
|
httpClient.setKeyStorePassword("storepwd");
|
||||||
|
httpClient.setKeyManagerPassword("keypwd");
|
||||||
|
httpClient.start();
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpHeaders;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.util.IO;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic Server Handler used for various client tests.
|
||||||
|
*/
|
||||||
|
public class GenericServerHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(GenericServerHandler.class);
|
||||||
|
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
response.setStatus(200);
|
||||||
|
|
||||||
|
if (request.getServerName().equals("jetty.eclipse.org"))
|
||||||
|
{
|
||||||
|
response.getOutputStream().println("Proxy request: " + request.getRequestURL());
|
||||||
|
response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
|
||||||
|
}
|
||||||
|
else if (request.getMethod().equalsIgnoreCase("GET"))
|
||||||
|
{
|
||||||
|
response.getOutputStream().println("<hello>");
|
||||||
|
for (; i < 100; i++)
|
||||||
|
{
|
||||||
|
response.getOutputStream().println(" <world>" + i + "</world");
|
||||||
|
if (i % 20 == 0)
|
||||||
|
response.getOutputStream().flush();
|
||||||
|
}
|
||||||
|
response.getOutputStream().println("</hello>");
|
||||||
|
}
|
||||||
|
else if (request.getMethod().equalsIgnoreCase("OPTIONS"))
|
||||||
|
{
|
||||||
|
if ("*".equals(target))
|
||||||
|
{
|
||||||
|
response.setContentLength(0);
|
||||||
|
response.setHeader("Allow","GET,HEAD,POST,PUT,DELETE,MOVE,OPTIONS,TRACE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request.getMethod().equalsIgnoreCase("SLEEP"))
|
||||||
|
{
|
||||||
|
Thread.sleep(10000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.setContentType(request.getContentType());
|
||||||
|
int size = request.getContentLength();
|
||||||
|
ByteArrayOutputStream bout = new ByteArrayOutputStream(size > 0?size:32768);
|
||||||
|
IO.copy(request.getInputStream(),bout);
|
||||||
|
response.getOutputStream().write(bout.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
LOG.debug(e);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
|
|
||||||
|
public class HttpServerAndClientCreator implements ServerAndClientCreator
|
||||||
|
{
|
||||||
|
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||||
|
{
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
httpClient.setIdleTimeout(idleTimeout);
|
||||||
|
httpClient.setTimeout(timeout);
|
||||||
|
httpClient.setConnectTimeout(connectTimeout);
|
||||||
|
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||||
|
httpClient.setMaxConnectionsPerAddress(2);
|
||||||
|
httpClient.start();
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Server createServer() throws Exception
|
||||||
|
{
|
||||||
|
Server _server = new Server();
|
||||||
|
_server.setGracefulShutdown(500);
|
||||||
|
Connector _connector = new SelectChannelConnector();
|
||||||
|
|
||||||
|
_connector.setMaxIdleTime(3000000);
|
||||||
|
|
||||||
|
_connector.setPort(0);
|
||||||
|
_server.setConnectors(new Connector[]{ _connector });
|
||||||
|
_server.setHandler(new GenericServerHandler());
|
||||||
|
_server.start();
|
||||||
|
return _server;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
|
||||||
|
public interface ServerAndClientCreator
|
||||||
|
{
|
||||||
|
Server createServer() throws Exception;
|
||||||
|
|
||||||
|
HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.eclipse.jetty.client.helperClasses;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
|
||||||
|
public class SslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||||
|
{
|
||||||
|
|
||||||
|
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||||
|
{
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
httpClient.setIdleTimeout(idleTimeout);
|
||||||
|
httpClient.setTimeout(timeout);
|
||||||
|
httpClient.setConnectTimeout(connectTimeout);
|
||||||
|
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||||
|
httpClient.setMaxConnectionsPerAddress(2);
|
||||||
|
httpClient.start();
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -155,157 +155,6 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
|
||||||
<id>unpack</id>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-rewrite</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-ajp</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>test-jetty-webapp</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-jmx</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-util</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-webapp</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-deploy</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-plus</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-server</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-security</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-policy</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-monitor</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-overlay-deployer</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-annotations</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<classifier>config</classifier>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
<execution>
|
||||||
<id>copy</id>
|
<id>copy</id>
|
||||||
<phase>generate-resources</phase>
|
<phase>generate-resources</phase>
|
||||||
|
@ -324,187 +173,6 @@
|
||||||
<outputDirectory>${assembly-directory}/</outputDirectory>
|
<outputDirectory>${assembly-directory}/</outputDirectory>
|
||||||
<destFileName>VERSION.txt</destFileName>
|
<destFileName>VERSION.txt</destFileName>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-util</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-io</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-http</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-server</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-security</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-servlet</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-servlets</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-xml</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-webapp</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<!-- Jetty Deploy -->
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-deploy</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-jmx</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-rewrite</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-ajp</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-annotations</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-client</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-jndi</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-policy</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-monitor</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-plus</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-continuation</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>test-jetty-webapp</artifactId>
|
<artifactId>test-jetty-webapp</artifactId>
|
||||||
|
@ -525,36 +193,77 @@
|
||||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||||
<destFileName>start.jar</destFileName>
|
<destFileName>start.jar</destFileName>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-overlay-deployer</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-overlay-deployer</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-websocket</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<overWrite>true</overWrite>
|
|
||||||
<includes>**</includes>
|
|
||||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
</artifactItems>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>copy-lib-deps</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||||
|
<excludeArtifactIds>jetty-start,jetty-monitor,jetty-jsp-2.1</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>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||||
|
<includeArtifactIds>jetty-monitor</includeArtifactIds>
|
||||||
|
<includeTypes>jar</includeTypes>
|
||||||
|
<excludeTransitive>true</excludeTransitive>
|
||||||
|
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>unpack-config-deps</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||||
|
<classifier>config</classifier>
|
||||||
|
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
|
||||||
|
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>unpack-javadoc</id>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<!-- Use already generated javadoc, don't bother regenerating again -->
|
||||||
|
<includeGroupIds>org.eclipse.jetty.aggregate</includeGroupIds>
|
||||||
|
<includeArtifactIds>jetty-all</includeArtifactIds>
|
||||||
|
<includeClassifier>javadoc</includeClassifier>
|
||||||
|
<excludeTransitive>true</excludeTransitive>
|
||||||
|
<outputDirectory>${assembly-directory}/javadoc</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -663,12 +372,12 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-overlay-deployer</artifactId>
|
<artifactId>jetty-servlets</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-overlay-deployer</artifactId>
|
<artifactId>jetty-monitor</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -676,5 +385,17 @@
|
||||||
<artifactId>jetty-websocket</artifactId>
|
<artifactId>jetty-websocket</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-overlay-deployer</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||||
|
<artifactId>jetty-all</artifactId>
|
||||||
|
<classifier>javadoc</classifier>
|
||||||
|
<type>jar</type>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -266,9 +266,19 @@ public class HttpParser implements Parser
|
||||||
// Fill buffer if we can
|
// Fill buffer if we can
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
{
|
{
|
||||||
long filled=fill();
|
long filled=-1;
|
||||||
|
IOException ex=null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
filled=fill();
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
LOG.debug(this.toString(),e);
|
||||||
|
ex=e;
|
||||||
|
}
|
||||||
|
|
||||||
if (filled < 0)
|
if (filled < 0 || _endp.isInputShutdown())
|
||||||
{
|
{
|
||||||
if (_headResponse && _state>STATE_END)
|
if (_headResponse && _state>STATE_END)
|
||||||
{
|
{
|
||||||
|
@ -291,6 +301,8 @@ public class HttpParser implements Parser
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ex!=null)
|
||||||
|
throw ex;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
length=_buffer.length();
|
length=_buffer.length();
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
// All rights reserved. This program and the accompanying materials
|
// All rights reserved. This program and the accompanying materials
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
// 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
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
// The Apache License v2.0 is available at
|
// The Apache License v2.0 is available at
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
// 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;
|
package org.eclipse.jetty.http;
|
||||||
|
@ -34,7 +34,7 @@ import org.eclipse.jetty.util.URIUtil;
|
||||||
* /foo/bar - an exact path specification.
|
* /foo/bar - an exact path specification.
|
||||||
* /foo/* - a prefix path specification (must end '/*').
|
* /foo/* - a prefix path specification (must end '/*').
|
||||||
* *.ext - a suffix path specification.
|
* *.ext - a suffix path specification.
|
||||||
* / - the default path specification.
|
* / - the default path specification.
|
||||||
* </PRE>
|
* </PRE>
|
||||||
* Matching is performed in the following order <NL>
|
* Matching is performed in the following order <NL>
|
||||||
* <LI>Exact match.
|
* <LI>Exact match.
|
||||||
|
@ -43,24 +43,24 @@ import org.eclipse.jetty.util.URIUtil;
|
||||||
* <LI>default.
|
* <LI>default.
|
||||||
* </NL>
|
* </NL>
|
||||||
* Multiple path specifications can be mapped by providing a list of
|
* Multiple path specifications can be mapped by providing a list of
|
||||||
* specifications. By default this class uses characters ":," as path
|
* specifications. By default this class uses characters ":," as path
|
||||||
* separators, unless configured differently by calling the static
|
* separators, unless configured differently by calling the static
|
||||||
* method @see PathMap#setPathSpecSeparators(String)
|
* method @see PathMap#setPathSpecSeparators(String)
|
||||||
* <P>
|
* <P>
|
||||||
* Special characters within paths such as '?<EFBFBD> and ';' are not treated specially
|
* Special characters within paths such as '?<EFBFBD> and ';' are not treated specially
|
||||||
* as it is assumed they would have been either encoded in the original URL or
|
* as it is assumed they would have been either encoded in the original URL or
|
||||||
* stripped from the path.
|
* stripped from the path.
|
||||||
* <P>
|
* <P>
|
||||||
* This class is not synchronized. If concurrent modifications are
|
* This class is not synchronized. If concurrent modifications are
|
||||||
* possible then it should be synchronized at a higher level.
|
* possible then it should be synchronized at a higher level.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PathMap extends HashMap implements Externalizable
|
public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private static String __pathSpecSeparators = ":,";
|
private static String __pathSpecSeparators = ":,";
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Set the path spec separator.
|
/** Set the path spec separator.
|
||||||
* Multiple path specification may be included in a single string
|
* Multiple path specification may be included in a single string
|
||||||
|
@ -72,7 +72,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
__pathSpecSeparators=s;
|
__pathSpecSeparators=s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
final StringMap _prefixMap=new StringMap();
|
final StringMap _prefixMap=new StringMap();
|
||||||
final StringMap _suffixMap=new StringMap();
|
final StringMap _suffixMap=new StringMap();
|
||||||
|
@ -83,7 +83,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
Entry _default=null;
|
Entry _default=null;
|
||||||
final Set _entrySet;
|
final Set _entrySet;
|
||||||
boolean _nodefault=false;
|
boolean _nodefault=false;
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Construct empty PathMap.
|
/** Construct empty PathMap.
|
||||||
*/
|
*/
|
||||||
|
@ -102,7 +102,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
_entrySet=entrySet();
|
_entrySet=entrySet();
|
||||||
_nodefault=nodefault;
|
_nodefault=nodefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Construct empty PathMap.
|
/** Construct empty PathMap.
|
||||||
*/
|
*/
|
||||||
|
@ -111,7 +111,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
super (capacity);
|
super (capacity);
|
||||||
_entrySet=entrySet();
|
_entrySet=entrySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Construct from dictionary PathMap.
|
/** Construct from dictionary PathMap.
|
||||||
*/
|
*/
|
||||||
|
@ -120,7 +120,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
putAll(m);
|
putAll(m);
|
||||||
_entrySet=entrySet();
|
_entrySet=entrySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void writeExternal(java.io.ObjectOutput out)
|
public void writeExternal(java.io.ObjectOutput out)
|
||||||
throws java.io.IOException
|
throws java.io.IOException
|
||||||
|
@ -128,7 +128,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
HashMap map = new HashMap(this);
|
HashMap map = new HashMap(this);
|
||||||
out.writeObject(map);
|
out.writeObject(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void readExternal(java.io.ObjectInput in)
|
public void readExternal(java.io.ObjectInput in)
|
||||||
throws java.io.IOException, ClassNotFoundException
|
throws java.io.IOException, ClassNotFoundException
|
||||||
|
@ -136,7 +136,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
HashMap map = (HashMap)in.readObject();
|
HashMap map = (HashMap)in.readObject();
|
||||||
this.putAll(map);
|
this.putAll(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Add a single path match to the PathMap.
|
/** Add a single path match to the PathMap.
|
||||||
* @param pathSpec The path specification, or comma separated list of
|
* @param pathSpec The path specification, or comma separated list of
|
||||||
|
@ -148,16 +148,16 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators);
|
StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators);
|
||||||
Object old =null;
|
Object old =null;
|
||||||
|
|
||||||
while (tok.hasMoreTokens())
|
while (tok.hasMoreTokens())
|
||||||
{
|
{
|
||||||
String spec=tok.nextToken();
|
String spec=tok.nextToken();
|
||||||
|
|
||||||
if (!spec.startsWith("/") && !spec.startsWith("*."))
|
if (!spec.startsWith("/") && !spec.startsWith("*."))
|
||||||
throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'");
|
throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'");
|
||||||
|
|
||||||
old = super.put(spec,object);
|
old = super.put(spec,object);
|
||||||
|
|
||||||
// Make entry that was just created.
|
// Make entry that was just created.
|
||||||
Entry entry = new Entry(spec,object);
|
Entry entry = new Entry(spec,object);
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
else if (spec.startsWith("*."))
|
else if (spec.startsWith("*."))
|
||||||
_suffixMap.put(spec.substring(2),entry);
|
_suffixMap.put(spec.substring(2),entry);
|
||||||
else if (spec.equals(URIUtil.SLASH))
|
else if (spec.equals(URIUtil.SLASH))
|
||||||
{
|
{
|
||||||
if (_nodefault)
|
if (_nodefault)
|
||||||
_exactMap.put(spec,entry);
|
_exactMap.put(spec,entry);
|
||||||
else
|
else
|
||||||
|
@ -193,7 +193,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,8 +209,8 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
return entry.getValue();
|
return entry.getValue();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Get the entry mapped by the best specification.
|
/** Get the entry mapped by the best specification.
|
||||||
* @param path the path.
|
* @param path the path.
|
||||||
|
@ -222,14 +222,14 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
|
|
||||||
if (path==null)
|
if (path==null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int l=path.length();
|
int l=path.length();
|
||||||
|
|
||||||
// try exact match
|
// try exact match
|
||||||
entry=_exactMap.getEntry(path,0,l);
|
entry=_exactMap.getEntry(path,0,l);
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
return (Entry) entry.getValue();
|
return (Entry) entry.getValue();
|
||||||
|
|
||||||
// prefix search
|
// prefix search
|
||||||
int i=l;
|
int i=l;
|
||||||
while((i=path.lastIndexOf('/',i-1))>=0)
|
while((i=path.lastIndexOf('/',i-1))>=0)
|
||||||
|
@ -238,11 +238,11 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
return (Entry) entry.getValue();
|
return (Entry) entry.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix Default
|
// Prefix Default
|
||||||
if (_prefixDefault!=null)
|
if (_prefixDefault!=null)
|
||||||
return _prefixDefault;
|
return _prefixDefault;
|
||||||
|
|
||||||
// Extension search
|
// Extension search
|
||||||
i=0;
|
i=0;
|
||||||
while ((i=path.indexOf('.',i+1))>0)
|
while ((i=path.indexOf('.',i+1))>0)
|
||||||
|
@ -250,12 +250,12 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
entry=_suffixMap.getEntry(path,i+1,l-i-1);
|
entry=_suffixMap.getEntry(path,i+1,l-i-1);
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
return (Entry) entry.getValue();
|
return (Entry) entry.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default
|
// Default
|
||||||
return _default;
|
return _default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Get all entries matched by the path.
|
/** Get all entries matched by the path.
|
||||||
* Best match first.
|
* Best match first.
|
||||||
|
@ -263,20 +263,20 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
* @return LazyList of Map.Entry instances key=pathSpec
|
* @return LazyList of Map.Entry instances key=pathSpec
|
||||||
*/
|
*/
|
||||||
public Object getLazyMatches(String path)
|
public Object getLazyMatches(String path)
|
||||||
{
|
{
|
||||||
Map.Entry entry;
|
Map.Entry entry;
|
||||||
Object entries=null;
|
Object entries=null;
|
||||||
|
|
||||||
if (path==null)
|
if (path==null)
|
||||||
return LazyList.getList(entries);
|
return LazyList.getList(entries);
|
||||||
|
|
||||||
int l=path.length();
|
int l=path.length();
|
||||||
|
|
||||||
// try exact match
|
// try exact match
|
||||||
entry=_exactMap.getEntry(path,0,l);
|
entry=_exactMap.getEntry(path,0,l);
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
entries=LazyList.add(entries,entry.getValue());
|
entries=LazyList.add(entries,entry.getValue());
|
||||||
|
|
||||||
// prefix search
|
// prefix search
|
||||||
int i=l-1;
|
int i=l-1;
|
||||||
while((i=path.lastIndexOf('/',i-1))>=0)
|
while((i=path.lastIndexOf('/',i-1))>=0)
|
||||||
|
@ -285,11 +285,11 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
entries=LazyList.add(entries,entry.getValue());
|
entries=LazyList.add(entries,entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix Default
|
// Prefix Default
|
||||||
if (_prefixDefault!=null)
|
if (_prefixDefault!=null)
|
||||||
entries=LazyList.add(entries,_prefixDefault);
|
entries=LazyList.add(entries,_prefixDefault);
|
||||||
|
|
||||||
// Extension search
|
// Extension search
|
||||||
i=0;
|
i=0;
|
||||||
while ((i=path.indexOf('.',i+1))>0)
|
while ((i=path.indexOf('.',i+1))>0)
|
||||||
|
@ -305,13 +305,13 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
// Optimization for just the default
|
// Optimization for just the default
|
||||||
if (entries==null)
|
if (entries==null)
|
||||||
return _defaultSingletonList;
|
return _defaultSingletonList;
|
||||||
|
|
||||||
entries=LazyList.add(entries,_default);
|
entries=LazyList.add(entries,_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Get all entries matched by the path.
|
/** Get all entries matched by the path.
|
||||||
* Best match first.
|
* Best match first.
|
||||||
|
@ -319,7 +319,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
* @return List of Map.Entry instances key=pathSpec
|
* @return List of Map.Entry instances key=pathSpec
|
||||||
*/
|
*/
|
||||||
public List getMatches(String path)
|
public List getMatches(String path)
|
||||||
{
|
{
|
||||||
return LazyList.getList(getLazyMatches(path));
|
return LazyList.getList(getLazyMatches(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,12 +330,12 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
* @return Whether the PathMap contains any entries that match this
|
* @return Whether the PathMap contains any entries that match this
|
||||||
*/
|
*/
|
||||||
public boolean containsMatch(String path)
|
public boolean containsMatch(String path)
|
||||||
{
|
{
|
||||||
Entry match = getMatch(path);
|
Entry match = getMatch(path);
|
||||||
return match!=null && !match.equals(_default);
|
return match!=null && !match.equals(_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
@Override
|
@Override
|
||||||
public Object remove(Object pathSpec)
|
public Object remove(Object pathSpec)
|
||||||
{
|
{
|
||||||
|
@ -362,7 +362,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
}
|
}
|
||||||
return super.remove(pathSpec);
|
return super.remove(pathSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
@Override
|
@Override
|
||||||
public void clear()
|
public void clear()
|
||||||
|
@ -374,7 +374,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
_defaultSingletonList=null;
|
_defaultSingletonList=null;
|
||||||
super.clear();
|
super.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* @return true if match.
|
* @return true if match.
|
||||||
|
@ -397,7 +397,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path))
|
if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(isPathWildcardMatch(pathSpec, path))
|
if(isPathWildcardMatch(pathSpec, path))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -419,24 +419,24 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Return the portion of a path that matches a path spec.
|
/** Return the portion of a path that matches a path spec.
|
||||||
* @return null if no match at all.
|
* @return null if no match at all.
|
||||||
*/
|
*/
|
||||||
public static String pathMatch(String pathSpec, String path)
|
public static String pathMatch(String pathSpec, String path)
|
||||||
{
|
{
|
||||||
char c = pathSpec.charAt(0);
|
char c = pathSpec.charAt(0);
|
||||||
|
|
||||||
if (c=='/')
|
if (c=='/')
|
||||||
{
|
{
|
||||||
if (pathSpec.length()==1)
|
if (pathSpec.length()==1)
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
if (pathSpec.equals(path))
|
if (pathSpec.equals(path))
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
if (isPathWildcardMatch(pathSpec, path))
|
if (isPathWildcardMatch(pathSpec, path))
|
||||||
return path.substring(0,pathSpec.length()-2);
|
return path.substring(0,pathSpec.length()-2);
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
/** Return the portion of a path that is after a path spec.
|
/** Return the portion of a path that is after a path spec.
|
||||||
* @return The path info string
|
* @return The path info string
|
||||||
|
@ -456,12 +456,12 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
public static String pathInfo(String pathSpec, String path)
|
public static String pathInfo(String pathSpec, String path)
|
||||||
{
|
{
|
||||||
char c = pathSpec.charAt(0);
|
char c = pathSpec.charAt(0);
|
||||||
|
|
||||||
if (c=='/')
|
if (c=='/')
|
||||||
{
|
{
|
||||||
if (pathSpec.length()==1)
|
if (pathSpec.length()==1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
boolean wildcard = isPathWildcardMatch(pathSpec, path);
|
boolean wildcard = isPathWildcardMatch(pathSpec, path);
|
||||||
|
|
||||||
// handle the case where pathSpec uses a wildcard and path info is "/*"
|
// handle the case where pathSpec uses a wildcard and path info is "/*"
|
||||||
|
@ -474,7 +474,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
return null;
|
return null;
|
||||||
return path.substring(pathSpec.length()-2);
|
return path.substring(pathSpec.length()-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
* @param base The base the path is relative to.
|
* @param base The base the path is relative to.
|
||||||
* @param pathSpec The spec of the path segment to ignore.
|
* @param pathSpec The spec of the path segment to ignore.
|
||||||
* @param path the additional path
|
* @param path the additional path
|
||||||
* @return base plus path with pathspec removed
|
* @return base plus path with pathspec removed
|
||||||
*/
|
*/
|
||||||
public static String relativePath(String base,
|
public static String relativePath(String base,
|
||||||
String pathSpec,
|
String pathSpec,
|
||||||
|
@ -508,7 +508,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
path = base + URIUtil.SLASH + info;
|
path = base + URIUtil.SLASH + info;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -516,7 +516,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
private final Object key;
|
private final Object key;
|
||||||
private final Object value;
|
private final Object value;
|
||||||
private String mapped;
|
private String mapped;
|
||||||
private transient String string;
|
private transient String string;
|
||||||
|
|
||||||
Entry(Object key, Object value)
|
Entry(Object key, Object value)
|
||||||
|
@ -529,7 +529,7 @@ public class PathMap extends HashMap implements Externalizable
|
||||||
{
|
{
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getValue()
|
public Object getValue()
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.security.InvalidParameterException;
|
import java.security.InvalidParameterException;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
@ -42,7 +43,10 @@ import javax.net.ssl.KeyManager;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLSessionContext;
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import javax.net.ssl.X509KeyManager;
|
import javax.net.ssl.X509KeyManager;
|
||||||
|
@ -51,6 +55,8 @@ import javax.net.ssl.X509TrustManager;
|
||||||
import org.eclipse.jetty.http.security.Password;
|
import org.eclipse.jetty.http.security.Password;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
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.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||||
import org.eclipse.jetty.util.security.CertificateValidator;
|
import org.eclipse.jetty.util.security.CertificateValidator;
|
||||||
|
@ -65,6 +71,8 @@ import org.eclipse.jetty.util.security.CertificateValidator;
|
||||||
*/
|
*/
|
||||||
public class SslContextFactory extends AbstractLifeCycle
|
public class SslContextFactory extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(SslContextFactory.class);
|
||||||
|
|
||||||
public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
|
public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
|
||||||
(Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
|
(Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
|
||||||
"SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
|
"SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
|
||||||
|
@ -82,8 +90,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
/** String name of keystore password property. */
|
/** String name of keystore password property. */
|
||||||
public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
|
public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
|
||||||
|
|
||||||
|
/** Excluded protocols. */
|
||||||
|
private final Set<String> _excludeProtocols = new HashSet<String>();
|
||||||
|
// private final Set<String> _excludeProtocols = new HashSet<String>(Collections.singleton("SSLv2Hello"));
|
||||||
|
/** Included protocols. */
|
||||||
|
private Set<String> _includeProtocols = null;
|
||||||
|
|
||||||
/** Excluded cipher suites. */
|
/** Excluded cipher suites. */
|
||||||
private Set<String> _excludeCipherSuites = null;
|
private final Set<String> _excludeCipherSuites = new HashSet<String>();
|
||||||
/** Included cipher suites. */
|
/** Included cipher suites. */
|
||||||
private Set<String> _includeCipherSuites = null;
|
private Set<String> _includeCipherSuites = null;
|
||||||
|
|
||||||
|
@ -196,6 +210,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
if (_keyStoreInputStream == null && _keyStorePath == null &&
|
if (_keyStoreInputStream == null && _keyStorePath == null &&
|
||||||
_trustStoreInputStream == null && _trustStorePath == 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
|
// Create a trust manager that does not validate certificate chains
|
||||||
TrustManager trustAllCerts = new X509TrustManager()
|
TrustManager trustAllCerts = new X509TrustManager()
|
||||||
{
|
{
|
||||||
|
@ -218,11 +233,115 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
createSSLContext();
|
// verify that keystore and truststore
|
||||||
|
// parameters are set up correctly
|
||||||
|
try
|
||||||
|
{
|
||||||
|
checkKeyStore();
|
||||||
|
}
|
||||||
|
catch(IllegalStateException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyStore keyStore = loadKeyStore();
|
||||||
|
KeyStore trustStore = loadTrustStore();
|
||||||
|
|
||||||
|
Collection<? extends CRL> crls = loadCRL(_crlPath);
|
||||||
|
|
||||||
|
if (_validateCerts && keyStore != null)
|
||||||
|
{
|
||||||
|
if (_certAlias == null)
|
||||||
|
{
|
||||||
|
List<String> aliases = Collections.list(keyStore.aliases());
|
||||||
|
_certAlias = aliases.size() == 1 ? aliases.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
|
||||||
|
if (cert == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
|
||||||
|
}
|
||||||
|
|
||||||
|
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||||
|
validator.setMaxCertPathLength(_maxCertPathLength);
|
||||||
|
validator.setEnableCRLDP(_enableCRLDP);
|
||||||
|
validator.setEnableOCSP(_enableOCSP);
|
||||||
|
validator.setOcspResponderURL(_ocspResponderURL);
|
||||||
|
validator.validate(keyStore, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyManager[] keyManagers = getKeyManagers(keyStore);
|
||||||
|
TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
|
||||||
|
|
||||||
|
SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
|
||||||
|
_context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
|
||||||
|
_context.init(keyManagers,trustManagers,secureRandom);
|
||||||
|
|
||||||
|
SSLEngine engine=newSslEngine();
|
||||||
|
LOG.info("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
|
||||||
|
LOG.debug("Enabled Ciphers {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return The array of protocol names to exclude from
|
||||||
|
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||||
|
*/
|
||||||
|
public String[] getExcludeProtocols()
|
||||||
|
{
|
||||||
|
return _excludeProtocols.toArray(new String[_excludeProtocols.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param Protocols
|
||||||
|
* The array of protocol names to exclude from
|
||||||
|
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||||
|
*/
|
||||||
|
public void setExcludeProtocols(String... protocols)
|
||||||
|
{
|
||||||
|
checkNotStarted();
|
||||||
|
|
||||||
|
_excludeProtocols.clear();
|
||||||
|
_excludeProtocols.addAll(Arrays.asList(protocols));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param protocol Protocol names to add to {@link SSLEngine#setEnabledProtocols(String[])}
|
||||||
|
*/
|
||||||
|
public void addExcludeProtocols(String... protocol)
|
||||||
|
{
|
||||||
|
checkNotStarted();
|
||||||
|
_excludeProtocols.addAll(Arrays.asList(protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return The array of protocol names to include in
|
||||||
|
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||||
|
*/
|
||||||
|
public String[] getIncludeProtocols()
|
||||||
|
{
|
||||||
|
return _includeProtocols.toArray(new String[_includeProtocols.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param Protocols
|
||||||
|
* The array of protocol names to include in
|
||||||
|
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||||
|
*/
|
||||||
|
public void setIncludeProtocols(String... protocols)
|
||||||
|
{
|
||||||
|
checkNotStarted();
|
||||||
|
|
||||||
|
_includeProtocols = new HashSet<String>(Arrays.asList(protocols));
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return The array of cipher suite names to exclude from
|
* @return The array of cipher suite names to exclude from
|
||||||
|
@ -239,11 +358,21 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
* The array of cipher suite names to exclude from
|
* The array of cipher suite names to exclude from
|
||||||
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||||
*/
|
*/
|
||||||
public void setExcludeCipherSuites(String[] cipherSuites)
|
public void setExcludeCipherSuites(String... cipherSuites)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
_excludeCipherSuites.clear();
|
||||||
_excludeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
|
_excludeCipherSuites.addAll(Arrays.asList(cipherSuites));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param cipher Cipher names to add to {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||||
|
*/
|
||||||
|
public void addExcludeCipherSuites(String... cipher)
|
||||||
|
{
|
||||||
|
checkNotStarted();
|
||||||
|
_excludeCipherSuites.addAll(Arrays.asList(cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -262,9 +391,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
* The array of cipher suite names to include in
|
* The array of cipher suite names to include in
|
||||||
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||||
*/
|
*/
|
||||||
public void setIncludeCipherSuites(String[] cipherSuites)
|
public void setIncludeCipherSuites(String... cipherSuites)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_includeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
|
_includeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
|
||||||
}
|
}
|
||||||
|
@ -285,7 +414,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStore(String keyStorePath)
|
public void setKeyStore(String keyStorePath)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStorePath = keyStorePath;
|
_keyStorePath = keyStorePath;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +435,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStoreProvider(String keyStoreProvider)
|
public void setKeyStoreProvider(String keyStoreProvider)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStoreProvider = keyStoreProvider;
|
_keyStoreProvider = keyStoreProvider;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +456,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStoreType(String keyStoreType)
|
public void setKeyStoreType(String keyStoreType)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStoreType = keyStoreType;
|
_keyStoreType = keyStoreType;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +470,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public InputStream getKeyStoreInputStream()
|
public InputStream getKeyStoreInputStream()
|
||||||
{
|
{
|
||||||
checkConfig();
|
checkKeyStore();
|
||||||
|
|
||||||
return _keyStoreInputStream;
|
return _keyStoreInputStream;
|
||||||
}
|
}
|
||||||
|
@ -355,7 +484,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStoreInputStream = keyStoreInputStream;
|
_keyStoreInputStream = keyStoreInputStream;
|
||||||
}
|
}
|
||||||
|
@ -376,7 +505,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setCertAlias(String certAlias)
|
public void setCertAlias(String certAlias)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_certAlias = certAlias;
|
_certAlias = certAlias;
|
||||||
}
|
}
|
||||||
|
@ -397,7 +526,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStore(String trustStorePath)
|
public void setTrustStore(String trustStorePath)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStorePath = trustStorePath;
|
_trustStorePath = trustStorePath;
|
||||||
}
|
}
|
||||||
|
@ -418,7 +547,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStoreProvider(String trustStoreProvider)
|
public void setTrustStoreProvider(String trustStoreProvider)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStoreProvider = trustStoreProvider;
|
_trustStoreProvider = trustStoreProvider;
|
||||||
}
|
}
|
||||||
|
@ -439,7 +568,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStoreType(String trustStoreType)
|
public void setTrustStoreType(String trustStoreType)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStoreType = trustStoreType;
|
_trustStoreType = trustStoreType;
|
||||||
}
|
}
|
||||||
|
@ -453,7 +582,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public InputStream getTrustStoreInputStream()
|
public InputStream getTrustStoreInputStream()
|
||||||
{
|
{
|
||||||
checkConfig();
|
checkKeyStore();
|
||||||
|
|
||||||
return _trustStoreInputStream;
|
return _trustStoreInputStream;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +596,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
|
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStoreInputStream = trustStoreInputStream;
|
_trustStoreInputStream = trustStoreInputStream;
|
||||||
}
|
}
|
||||||
|
@ -490,7 +619,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setNeedClientAuth(boolean needClientAuth)
|
public void setNeedClientAuth(boolean needClientAuth)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_needClientAuth = needClientAuth;
|
_needClientAuth = needClientAuth;
|
||||||
}
|
}
|
||||||
|
@ -513,7 +642,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setWantClientAuth(boolean wantClientAuth)
|
public void setWantClientAuth(boolean wantClientAuth)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_wantClientAuth = wantClientAuth;
|
_wantClientAuth = wantClientAuth;
|
||||||
}
|
}
|
||||||
|
@ -545,7 +674,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setValidateCerts(boolean validateCerts)
|
public void setValidateCerts(boolean validateCerts)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_validateCerts = validateCerts;
|
_validateCerts = validateCerts;
|
||||||
}
|
}
|
||||||
|
@ -566,7 +695,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setValidatePeerCerts(boolean validatePeerCerts)
|
public void setValidatePeerCerts(boolean validatePeerCerts)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_validatePeerCerts = validatePeerCerts;
|
_validatePeerCerts = validatePeerCerts;
|
||||||
}
|
}
|
||||||
|
@ -593,7 +722,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_allowRenegotiate = allowRenegotiate;
|
_allowRenegotiate = allowRenegotiate;
|
||||||
}
|
}
|
||||||
|
@ -605,7 +734,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStorePassword(String password)
|
public void setKeyStorePassword(String password)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
_keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
||||||
}
|
}
|
||||||
|
@ -617,7 +746,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyManagerPassword(String password)
|
public void setKeyManagerPassword(String password)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
|
_keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
|
||||||
}
|
}
|
||||||
|
@ -629,7 +758,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStorePassword(String password)
|
public void setTrustStorePassword(String password)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
||||||
}
|
}
|
||||||
|
@ -652,7 +781,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setProvider(String provider)
|
public void setProvider(String provider)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_sslProvider = provider;
|
_sslProvider = provider;
|
||||||
}
|
}
|
||||||
|
@ -675,7 +804,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setProtocol(String protocol)
|
public void setProtocol(String protocol)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_sslProtocol = protocol;
|
_sslProtocol = protocol;
|
||||||
}
|
}
|
||||||
|
@ -700,7 +829,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setSecureRandomAlgorithm(String algorithm)
|
public void setSecureRandomAlgorithm(String algorithm)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_secureRandomAlgorithm = algorithm;
|
_secureRandomAlgorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
@ -721,7 +850,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyManagerFactoryAlgorithm = algorithm;
|
_keyManagerFactoryAlgorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
@ -742,7 +871,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustManagerFactoryAlgorithm(String algorithm)
|
public void setTrustManagerFactoryAlgorithm(String algorithm)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustManagerFactoryAlgorithm = algorithm;
|
_trustManagerFactoryAlgorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
@ -763,7 +892,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setCrlPath(String crlPath)
|
public void setCrlPath(String crlPath)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_crlPath = crlPath;
|
_crlPath = crlPath;
|
||||||
}
|
}
|
||||||
|
@ -786,7 +915,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setMaxCertPathLength(int maxCertPathLength)
|
public void setMaxCertPathLength(int maxCertPathLength)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_maxCertPathLength = maxCertPathLength;
|
_maxCertPathLength = maxCertPathLength;
|
||||||
}
|
}
|
||||||
|
@ -797,6 +926,8 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public SSLContext getSslContext()
|
public SSLContext getSslContext()
|
||||||
{
|
{
|
||||||
|
if (!isStarted())
|
||||||
|
throw new IllegalStateException(getState());
|
||||||
return _context;
|
return _context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,60 +938,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setSslContext(SSLContext sslContext)
|
public void setSslContext(SSLContext sslContext)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_context = sslContext;
|
_context = sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected void createSSLContext() throws Exception
|
|
||||||
{
|
|
||||||
// verify that keystore and truststore
|
|
||||||
// parameters are set up correctly
|
|
||||||
checkConfig();
|
|
||||||
|
|
||||||
KeyStore keyStore = loadKeyStore();
|
|
||||||
KeyStore trustStore = loadTrustStore();
|
|
||||||
|
|
||||||
Collection<? extends CRL> crls = loadCRL(_crlPath);
|
|
||||||
|
|
||||||
if (_validateCerts && keyStore != null)
|
|
||||||
{
|
|
||||||
if (_certAlias == null)
|
|
||||||
{
|
|
||||||
List<String> aliases = Collections.list(keyStore.aliases());
|
|
||||||
_certAlias = aliases.size() == 1 ? aliases.get(0) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
|
|
||||||
if (cert == null)
|
|
||||||
{
|
|
||||||
throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
|
|
||||||
}
|
|
||||||
|
|
||||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
|
||||||
validator.setMaxCertPathLength(_maxCertPathLength);
|
|
||||||
validator.setEnableCRLDP(_enableCRLDP);
|
|
||||||
validator.setEnableOCSP(_enableOCSP);
|
|
||||||
validator.setOcspResponderURL(_ocspResponderURL);
|
|
||||||
validator.validate(keyStore, cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyManager[] keyManagers = getKeyManagers(keyStore);
|
|
||||||
TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
|
|
||||||
|
|
||||||
SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
|
|
||||||
_context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
|
|
||||||
_context.init(keyManagers,trustManagers,secureRandom);
|
|
||||||
|
|
||||||
SSLSessionContext sslSessionContext = _context.getServerSessionContext();
|
|
||||||
sslSessionContext.setSessionCacheSize(_sslSessionCacheSize);
|
|
||||||
sslSessionContext.setSessionTimeout(_sslSessionTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Override this method to provide alternate way to load a keystore.
|
* Override this method to provide alternate way to load a keystore.
|
||||||
|
@ -1014,33 +1096,27 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Check configuration. Ensures that if keystore has been
|
* Check KetyStore Configuration. Ensures that if keystore has been
|
||||||
* configured but there's no truststore, that keystore is
|
* configured but there's no truststore, that keystore is
|
||||||
* used as truststore.
|
* used as truststore.
|
||||||
* @return true SslContextFactory configuration can be used in server connector.
|
* @throws IllegalStateException if SslContextFactory configuration can't be used.
|
||||||
*/
|
*/
|
||||||
public boolean checkConfig()
|
public void checkKeyStore()
|
||||||
{
|
{
|
||||||
boolean check = true;
|
|
||||||
if (_keyStore == null && _keyStoreInputStream == null && _keyStorePath == null)
|
if (_keyStore == null && _keyStoreInputStream == null && _keyStorePath == null)
|
||||||
|
throw new IllegalStateException("SSL doesn't have a valid keystore");
|
||||||
|
|
||||||
|
// if the keystore has been configured but there is no
|
||||||
|
// truststore configured, use the keystore as the truststore
|
||||||
|
if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
|
||||||
{
|
{
|
||||||
// configuration doesn't have a valid keystore
|
_trustStore = _keyStore;
|
||||||
check = false;
|
_trustStorePath = _keyStorePath;
|
||||||
}
|
_trustStoreInputStream = _keyStoreInputStream;
|
||||||
else
|
_trustStoreType = _keyStoreType;
|
||||||
{
|
_trustStoreProvider = _keyStoreProvider;
|
||||||
// if the keystore has been configured but there is no
|
_trustStorePassword = _keyStorePassword;
|
||||||
// truststore configured, use the keystore as the truststore
|
_trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
|
||||||
if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
|
|
||||||
{
|
|
||||||
_trustStore = _keyStore;
|
|
||||||
_trustStorePath = _keyStorePath;
|
|
||||||
_trustStoreInputStream = _keyStoreInputStream;
|
|
||||||
_trustStoreType = _keyStoreType;
|
|
||||||
_trustStoreProvider = _keyStoreProvider;
|
|
||||||
_trustStorePassword = _keyStorePassword;
|
|
||||||
_trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's the same stream we cannot read it twice, so read it once in memory
|
// It's the same stream we cannot read it twice, so read it once in memory
|
||||||
|
@ -1057,11 +1133,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new RuntimeException(ex);
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return check;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -1073,57 +1147,68 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
* @param supportedCipherSuites Array of supported cipher suites
|
* @param supportedCipherSuites Array of supported cipher suites
|
||||||
* @return Array of cipher suites to enable
|
* @return Array of cipher suites to enable
|
||||||
*/
|
*/
|
||||||
public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
|
public String[] selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
|
||||||
{
|
{
|
||||||
Set<String> selectedCipherSuites = null;
|
Set<String> selected_protocols = new HashSet<String>();
|
||||||
if (enabledCipherSuites != null)
|
|
||||||
|
// Set the starting protocols - either from the included or enabled list
|
||||||
|
if (_includeProtocols!=null)
|
||||||
{
|
{
|
||||||
selectedCipherSuites = new HashSet<String>(Arrays.asList(enabledCipherSuites));
|
// Use only the supported included protocols
|
||||||
|
for (String protocol : supportedProtocols)
|
||||||
|
if (_includeProtocols.contains(protocol))
|
||||||
|
selected_protocols.add(protocol);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
selected_protocols.addAll(Arrays.asList(enabledProtocols));
|
||||||
|
|
||||||
|
|
||||||
|
// Remove any excluded protocols
|
||||||
|
if (_excludeProtocols != null)
|
||||||
|
selected_protocols.removeAll(_excludeProtocols);
|
||||||
|
|
||||||
|
return selected_protocols.toArray(new String[selected_protocols.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* Select cipher suites to be used by the connector
|
||||||
|
* based on configured inclusion and exclusion lists
|
||||||
|
* as well as enabled and supported cipher suite lists.
|
||||||
|
* @param enabledCipherSuites Array of enabled cipher suites
|
||||||
|
* @param supportedCipherSuites Array of supported cipher suites
|
||||||
|
* @return Array of cipher suites to enable
|
||||||
|
*/
|
||||||
|
public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
|
||||||
|
{
|
||||||
|
Set<String> selected_ciphers = new HashSet<String>();
|
||||||
|
|
||||||
|
// Set the starting ciphers - either from the included or enabled list
|
||||||
|
if (_includeCipherSuites!=null)
|
||||||
{
|
{
|
||||||
selectedCipherSuites = new HashSet<String>();
|
// Use only the supported included ciphers
|
||||||
|
for (String cipherSuite : supportedCipherSuites)
|
||||||
|
if (_includeCipherSuites.contains(cipherSuite))
|
||||||
|
selected_ciphers.add(cipherSuite);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if ((supportedCipherSuites != null && supportedCipherSuites.length > 0) &&
|
selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
|
||||||
(_includeCipherSuites != null && _includeCipherSuites.size() > 0))
|
|
||||||
{
|
|
||||||
Set<String> supportedCSList = new HashSet<String>(Arrays.asList(supportedCipherSuites));
|
// Remove any excluded ciphers
|
||||||
|
if (_excludeCipherSuites != null)
|
||||||
for (String cipherName : _includeCipherSuites)
|
selected_ciphers.removeAll(_excludeCipherSuites);
|
||||||
{
|
return selected_ciphers.toArray(new String[selected_ciphers.size()]);
|
||||||
if ((!selectedCipherSuites.contains(cipherName)) &&
|
|
||||||
supportedCSList.contains(cipherName))
|
|
||||||
{
|
|
||||||
selectedCipherSuites.add(cipherName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_excludeCipherSuites != null && _excludeCipherSuites.size() > 0)
|
|
||||||
{
|
|
||||||
for (String cipherName : _excludeCipherSuites)
|
|
||||||
{
|
|
||||||
if (selectedCipherSuites.contains(cipherName))
|
|
||||||
{
|
|
||||||
selectedCipherSuites.remove(cipherName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectedCipherSuites.toArray(new String[selectedCipherSuites.size()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Check if the lifecycle has been started and throw runtime exception
|
* Check if the lifecycle has been started and throw runtime exception
|
||||||
*/
|
*/
|
||||||
protected void checkStarted()
|
protected void checkNotStarted()
|
||||||
{
|
{
|
||||||
if (isStarted())
|
if (isStarted())
|
||||||
{
|
throw new IllegalStateException("Cannot modify configuration when "+getState());
|
||||||
throw new IllegalStateException("Cannot modify configuration after SslContextFactory was started");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -1141,7 +1226,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setEnableCRLDP(boolean enableCRLDP)
|
public void setEnableCRLDP(boolean enableCRLDP)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_enableCRLDP = enableCRLDP;
|
_enableCRLDP = enableCRLDP;
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1246,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setEnableOCSP(boolean enableOCSP)
|
public void setEnableOCSP(boolean enableOCSP)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_enableOCSP = enableOCSP;
|
_enableOCSP = enableOCSP;
|
||||||
}
|
}
|
||||||
|
@ -1181,7 +1266,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setOcspResponderURL(String ocspResponderURL)
|
public void setOcspResponderURL(String ocspResponderURL)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_ocspResponderURL = ocspResponderURL;
|
_ocspResponderURL = ocspResponderURL;
|
||||||
}
|
}
|
||||||
|
@ -1192,7 +1277,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStore(KeyStore keyStore)
|
public void setKeyStore(KeyStore keyStore)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_keyStore = keyStore;
|
_keyStore = keyStore;
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1288,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStore(KeyStore trustStore)
|
public void setTrustStore(KeyStore trustStore)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
_trustStore = trustStore;
|
_trustStore = trustStore;
|
||||||
}
|
}
|
||||||
|
@ -1214,7 +1299,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setKeyStoreResource(Resource resource)
|
public void setKeyStoreResource(Resource resource)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1233,7 +1318,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
*/
|
*/
|
||||||
public void setTrustStore(Resource resource)
|
public void setTrustStore(Resource resource)
|
||||||
{
|
{
|
||||||
checkStarted();
|
checkNotStarted();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1299,4 +1384,83 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
_sslSessionTimeout = sslSessionTimeout;
|
_sslSessionTimeout = sslSessionTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException
|
||||||
|
{
|
||||||
|
SSLServerSocketFactory factory = _context.getServerSocketFactory();
|
||||||
|
|
||||||
|
SSLServerSocket socket =
|
||||||
|
(SSLServerSocket) (host==null ?
|
||||||
|
factory.createServerSocket(port,backlog):
|
||||||
|
factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
|
||||||
|
|
||||||
|
if (getWantClientAuth())
|
||||||
|
socket.setWantClientAuth(getWantClientAuth());
|
||||||
|
if (getNeedClientAuth())
|
||||||
|
socket.setNeedClientAuth(getNeedClientAuth());
|
||||||
|
|
||||||
|
socket.setEnabledCipherSuites(selectCipherSuites(
|
||||||
|
socket.getEnabledCipherSuites(),
|
||||||
|
socket.getSupportedCipherSuites()));
|
||||||
|
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public SSLSocket newSslSocket() throws IOException
|
||||||
|
{
|
||||||
|
SSLSocketFactory factory = _context.getSocketFactory();
|
||||||
|
|
||||||
|
SSLSocket socket = (SSLSocket)factory.createSocket();
|
||||||
|
|
||||||
|
if (getWantClientAuth())
|
||||||
|
socket.setWantClientAuth(getWantClientAuth());
|
||||||
|
if (getNeedClientAuth())
|
||||||
|
socket.setNeedClientAuth(getNeedClientAuth());
|
||||||
|
|
||||||
|
socket.setEnabledCipherSuites(selectCipherSuites(
|
||||||
|
socket.getEnabledCipherSuites(),
|
||||||
|
socket.getSupportedCipherSuites()));
|
||||||
|
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public SSLEngine newSslEngine(String host,int port)
|
||||||
|
{
|
||||||
|
SSLEngine sslEngine=isSessionCachingEnabled()
|
||||||
|
?_context.createSSLEngine(host, port)
|
||||||
|
:_context.createSSLEngine();
|
||||||
|
|
||||||
|
customize(sslEngine);
|
||||||
|
return sslEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public SSLEngine newSslEngine()
|
||||||
|
{
|
||||||
|
SSLEngine sslEngine=_context.createSSLEngine();
|
||||||
|
customize(sslEngine);
|
||||||
|
return sslEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void customize(SSLEngine sslEngine)
|
||||||
|
{
|
||||||
|
if (getWantClientAuth())
|
||||||
|
sslEngine.setWantClientAuth(getWantClientAuth());
|
||||||
|
if (getNeedClientAuth())
|
||||||
|
sslEngine.setNeedClientAuth(getNeedClientAuth());
|
||||||
|
|
||||||
|
sslEngine.setEnabledCipherSuites(selectCipherSuites(
|
||||||
|
sslEngine.getEnabledCipherSuites(),
|
||||||
|
sslEngine.getSupportedCipherSuites()));
|
||||||
|
|
||||||
|
sslEngine.setEnabledProtocols(selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,9 +109,12 @@ public class ChannelEndPoint implements EndPoint
|
||||||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||||
{
|
{
|
||||||
Socket socket= ((SocketChannel)_channel).socket();
|
Socket socket= ((SocketChannel)_channel).socket();
|
||||||
if (!socket.isClosed()&&!socket.isInputShutdown())
|
if (!socket.isClosed())
|
||||||
{
|
{
|
||||||
socket.shutdownInput();
|
if(socket.isOutputShutdown())
|
||||||
|
socket.close();
|
||||||
|
else if (!socket.isInputShutdown())
|
||||||
|
socket.shutdownInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,9 +127,12 @@ public class ChannelEndPoint implements EndPoint
|
||||||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||||
{
|
{
|
||||||
Socket socket= ((SocketChannel)_channel).socket();
|
Socket socket= ((SocketChannel)_channel).socket();
|
||||||
if (!socket.isClosed()&&!socket.isOutputShutdown())
|
if (!socket.isClosed())
|
||||||
{
|
{
|
||||||
socket.shutdownOutput();
|
if (socket.isInputShutdown())
|
||||||
|
socket.close();
|
||||||
|
else if (!socket.isOutputShutdown())
|
||||||
|
socket.shutdownOutput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,8 +166,8 @@ public class ChannelEndPoint implements EndPoint
|
||||||
{
|
{
|
||||||
final NIOBuffer nbuf = (NIOBuffer)buf;
|
final NIOBuffer nbuf = (NIOBuffer)buf;
|
||||||
final ByteBuffer bbuf=nbuf.getByteBuffer();
|
final ByteBuffer bbuf=nbuf.getByteBuffer();
|
||||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
|
||||||
|
|
||||||
|
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
synchronized(bbuf)
|
synchronized(bbuf)
|
||||||
|
@ -178,13 +184,17 @@ public class ChannelEndPoint implements EndPoint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len<0 && isOpen() && !isInputShutdown())
|
if (len<0 && isOpen())
|
||||||
{
|
{
|
||||||
shutdownInput();
|
if (!isInputShutdown())
|
||||||
|
shutdownInput();
|
||||||
|
else if (isOutputShutdown())
|
||||||
|
_channel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException x)
|
catch (IOException x)
|
||||||
{
|
{
|
||||||
|
LOG.debug(x);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
@ -196,7 +206,6 @@ public class ChannelEndPoint implements EndPoint
|
||||||
|
|
||||||
if (len>0)
|
if (len>0)
|
||||||
throw x;
|
throw x;
|
||||||
LOG.ignore(x);
|
|
||||||
len=-1;
|
len=-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
*/
|
*/
|
||||||
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
|
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
|
||||||
{
|
{
|
||||||
public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio");
|
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||||
|
|
||||||
private final SelectorManager.SelectSet _selectSet;
|
private final SelectorManager.SelectSet _selectSet;
|
||||||
private final SelectorManager _manager;
|
private final SelectorManager _manager;
|
||||||
|
@ -54,7 +54,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
private boolean _writeBlocked;
|
private boolean _writeBlocked;
|
||||||
private boolean _open;
|
private boolean _open;
|
||||||
private volatile long _idleTimestamp;
|
private volatile long _idleTimestamp;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
|
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
@ -90,6 +90,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
|
|
||||||
scheduleIdle();
|
scheduleIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public SelectionKey getSelectionKey()
|
public SelectionKey getSelectionKey()
|
||||||
{
|
{
|
||||||
|
@ -205,7 +206,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
if(!dispatched)
|
if(!dispatched)
|
||||||
{
|
{
|
||||||
_dispatched = false;
|
_dispatched = false;
|
||||||
__log.warn("Dispatched Failed! "+this+" to "+_manager);
|
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
|
||||||
updateKey();
|
updateKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +251,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
public void checkIdleTimestamp(long now)
|
public void checkIdleTimestamp(long now)
|
||||||
{
|
{
|
||||||
long idleTimestamp=_idleTimestamp;
|
long idleTimestamp=_idleTimestamp;
|
||||||
if (idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
|
if (!getChannel().isOpen() || idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
|
||||||
idleExpired();
|
idleExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +261,15 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
_connection.idleExpired();
|
_connection.idleExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return True if the endpoint has produced/consumed bytes itself (non application data).
|
||||||
|
*/
|
||||||
|
public boolean isProgressing()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
@ -340,7 +350,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
catch (InterruptedException e)
|
catch (InterruptedException e)
|
||||||
{
|
{
|
||||||
__log.warn(e);
|
LOG.warn(e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -385,7 +395,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
catch (InterruptedException e)
|
catch (InterruptedException e)
|
||||||
{
|
{
|
||||||
__log.warn(e);
|
LOG.warn(e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -398,7 +408,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
catch(Throwable e)
|
catch(Throwable e)
|
||||||
{
|
{
|
||||||
// TODO remove this if it finds nothing
|
// TODO remove this if it finds nothing
|
||||||
__log.warn(e);
|
LOG.warn(e);
|
||||||
if (e instanceof RuntimeException)
|
if (e instanceof RuntimeException)
|
||||||
throw (RuntimeException)e;
|
throw (RuntimeException)e;
|
||||||
if (e instanceof Error)
|
if (e instanceof Error)
|
||||||
|
@ -414,10 +424,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* short cut for busyselectChannelServerTest */
|
||||||
|
public void clearWritable()
|
||||||
|
{
|
||||||
|
_writable=false;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void scheduleWrite()
|
public void scheduleWrite()
|
||||||
{
|
{
|
||||||
|
if (_writable==true)
|
||||||
|
LOG.debug("Required scheduleWrite {}",this);
|
||||||
|
|
||||||
_writable=false;
|
_writable=false;
|
||||||
updateKey();
|
updateKey();
|
||||||
}
|
}
|
||||||
|
@ -445,7 +465,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
_key=null;
|
_key=null;
|
||||||
__log.ignore(e);
|
LOG.ignore(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,7 +503,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
__log.ignore(e);
|
LOG.ignore(e);
|
||||||
if (_key!=null && _key.isValid())
|
if (_key!=null && _key.isValid())
|
||||||
{
|
{
|
||||||
_key.cancel();
|
_key.cancel();
|
||||||
|
@ -520,9 +540,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
cancelIdle();
|
cancelIdle();
|
||||||
if (_open)
|
if (_open)
|
||||||
{
|
{
|
||||||
|
_open=false;
|
||||||
_selectSet.destroyEndPoint(this);
|
_selectSet.destroyEndPoint(this);
|
||||||
}
|
}
|
||||||
_open=false;
|
|
||||||
_key = null;
|
_key = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -545,7 +565,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
final Connection next = _connection.handle();
|
final Connection next = _connection.handle();
|
||||||
if (next!=_connection)
|
if (next!=_connection)
|
||||||
{
|
{
|
||||||
__log.debug("{} replaced {}",next,_connection);
|
LOG.debug("{} replaced {}",next,_connection);
|
||||||
_connection=next;
|
_connection=next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -554,26 +574,26 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
catch (ClosedChannelException e)
|
catch (ClosedChannelException e)
|
||||||
{
|
{
|
||||||
__log.ignore(e);
|
LOG.ignore(e);
|
||||||
}
|
}
|
||||||
catch (EofException e)
|
catch (EofException e)
|
||||||
{
|
{
|
||||||
__log.debug("EOF", e);
|
LOG.debug("EOF", e);
|
||||||
try{close();}
|
try{getChannel().close();}
|
||||||
catch(IOException e2){__log.ignore(e2);}
|
catch(IOException e2){LOG.ignore(e2);}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
__log.warn(e.toString());
|
LOG.warn(e.toString());
|
||||||
__log.debug(e);
|
LOG.debug(e);
|
||||||
try{close();}
|
try{getChannel().close();}
|
||||||
catch(IOException e2){__log.ignore(e2);}
|
catch(IOException e2){LOG.ignore(e2);}
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
__log.warn("handle failed", e);
|
LOG.warn("handle failed", e);
|
||||||
try{close();}
|
try{getChannel().close();}
|
||||||
catch(IOException e2){__log.ignore(e2);}
|
catch(IOException e2){LOG.ignore(e2);}
|
||||||
}
|
}
|
||||||
dispatched=!undispatch();
|
dispatched=!undispatch();
|
||||||
}
|
}
|
||||||
|
@ -585,7 +605,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
dispatched=!undispatch();
|
dispatched=!undispatch();
|
||||||
while (dispatched)
|
while (dispatched)
|
||||||
{
|
{
|
||||||
__log.warn("SCEP.run() finally DISPATCHED");
|
LOG.warn("SCEP.run() finally DISPATCHED");
|
||||||
dispatched=!undispatch();
|
dispatched=!undispatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,7 +625,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
__log.ignore(e);
|
LOG.ignore(e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -620,7 +640,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
synchronized(this)
|
synchronized(this)
|
||||||
{
|
{
|
||||||
return "SCEP@" + hashCode() + _channel+
|
return "SCEP@" + hashCode() + _channel+
|
||||||
"[d=" + _dispatched + ",io=" + _interestOps+
|
"[o="+isOpen()+" d=" + _dispatched + ",io=" + _interestOps+
|
||||||
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
|
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
// All rights reserved. This program and the accompanying materials
|
// All rights reserved. This program and the accompanying materials
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
// 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
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
// The Apache License v2.0 is available at
|
// The Apache License v2.0 is available at
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
// 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.nio;
|
package org.eclipse.jetty.io.nio;
|
||||||
|
@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||||
import org.eclipse.jetty.io.Connection;
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
@ -49,21 +48,16 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
|
||||||
* The Selector Manager manages and number of SelectSets to allow
|
* The Selector Manager manages and number of SelectSets to allow
|
||||||
* NIO scheduling to scale to large numbers of connections.
|
* NIO scheduling to scale to large numbers of connections.
|
||||||
* <p>
|
* <p>
|
||||||
* This class works around a number of know JVM bugs. For details
|
|
||||||
* see http://wiki.eclipse.org/Jetty/Feature/JVM_NIO_Bug
|
|
||||||
*/
|
*/
|
||||||
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
|
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
|
||||||
{
|
{
|
||||||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||||
|
|
||||||
// TODO Tune these by approx system speed.
|
|
||||||
private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",0).intValue();
|
|
||||||
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
|
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",25000).intValue();
|
||||||
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
|
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
|
||||||
private static final int __BUSY_KEY=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_KEY",-1).intValue();
|
|
||||||
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
|
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
|
||||||
|
|
||||||
private int _maxIdleTime;
|
private int _maxIdleTime;
|
||||||
private int _lowResourcesMaxIdleTime;
|
private int _lowResourcesMaxIdleTime;
|
||||||
private long _lowResourcesConnections;
|
private long _lowResourcesConnections;
|
||||||
|
@ -72,7 +66,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
private volatile int _set;
|
private volatile int _set;
|
||||||
private boolean _deferringInterestedOps0=true;
|
private boolean _deferringInterestedOps0=true;
|
||||||
private int _selectorPriorityDelta=0;
|
private int _selectorPriorityDelta=0;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed.
|
* @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed.
|
||||||
|
@ -82,18 +76,18 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
_maxIdleTime=(int)maxIdleTime;
|
_maxIdleTime=(int)maxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @param selectSets number of select sets to create
|
* @param selectSets number of select sets to create
|
||||||
*/
|
*/
|
||||||
public void setSelectSets(int selectSets)
|
public void setSelectSets(int selectSets)
|
||||||
{
|
{
|
||||||
long lrc = _lowResourcesConnections * _selectSets;
|
long lrc = _lowResourcesConnections * _selectSets;
|
||||||
_selectSets=selectSets;
|
_selectSets=selectSets;
|
||||||
_lowResourcesConnections=lrc/_selectSets;
|
_lowResourcesConnections=lrc/_selectSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return the max idle time
|
* @return the max idle time
|
||||||
|
@ -102,7 +96,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
return _maxIdleTime;
|
return _maxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return the number of select sets in use
|
* @return the number of select sets in use
|
||||||
|
@ -114,14 +108,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @param i
|
* @param i
|
||||||
* @return The select set
|
* @return The select set
|
||||||
*/
|
*/
|
||||||
public SelectSet getSelectSet(int i)
|
public SelectSet getSelectSet(int i)
|
||||||
{
|
{
|
||||||
return _selectSet[i];
|
return _selectSet[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Register a channel
|
/** Register a channel
|
||||||
* @param channel
|
* @param channel
|
||||||
|
@ -132,8 +126,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
// The ++ increment here is not atomic, but it does not matter.
|
// The ++ increment here is not atomic, but it does not matter.
|
||||||
// so long as the value changes sometimes, then connections will
|
// so long as the value changes sometimes, then connections will
|
||||||
// be distributed over the available sets.
|
// be distributed over the available sets.
|
||||||
|
|
||||||
int s=_set++;
|
int s=_set++;
|
||||||
s=s%_selectSets;
|
s=s%_selectSets;
|
||||||
SelectSet[] sets=_selectSet;
|
SelectSet[] sets=_selectSet;
|
||||||
if (sets!=null)
|
if (sets!=null)
|
||||||
|
@ -144,7 +138,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Register a channel
|
/** Register a channel
|
||||||
* @param channel
|
* @param channel
|
||||||
|
@ -154,8 +148,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
// The ++ increment here is not atomic, but it does not matter.
|
// The ++ increment here is not atomic, but it does not matter.
|
||||||
// so long as the value changes sometimes, then connections will
|
// so long as the value changes sometimes, then connections will
|
||||||
// be distributed over the available sets.
|
// be distributed over the available sets.
|
||||||
|
|
||||||
int s=_set++;
|
int s=_set++;
|
||||||
s=s%_selectSets;
|
s=s%_selectSets;
|
||||||
SelectSet[] sets=_selectSet;
|
SelectSet[] sets=_selectSet;
|
||||||
if (sets!=null)
|
if (sets!=null)
|
||||||
|
@ -165,14 +159,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
set.wakeup();
|
set.wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Register a {@link ServerSocketChannel}
|
/** Register a {@link ServerSocketChannel}
|
||||||
* @param acceptChannel
|
* @param acceptChannel
|
||||||
*/
|
*/
|
||||||
public void register(ServerSocketChannel acceptChannel)
|
public void register(ServerSocketChannel acceptChannel)
|
||||||
{
|
{
|
||||||
int s=_set++;
|
int s=_set++;
|
||||||
s=s%_selectSets;
|
s=s%_selectSets;
|
||||||
SelectSet set=_selectSet[s];
|
SelectSet set=_selectSet[s];
|
||||||
set.addChange(acceptChannel);
|
set.addChange(acceptChannel);
|
||||||
|
@ -196,8 +190,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
_selectorPriorityDelta=delta;
|
_selectorPriorityDelta=delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return the lowResourcesConnections
|
* @return the lowResourcesConnections
|
||||||
|
@ -237,7 +231,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
|
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
public abstract boolean dispatch(Runnable task);
|
public abstract boolean dispatch(Runnable task);
|
||||||
|
@ -254,7 +248,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
_selectSet[i]= new SelectSet(i);
|
_selectSet[i]= new SelectSet(i);
|
||||||
|
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
|
||||||
// start a thread to Select
|
// start a thread to Select
|
||||||
for (int i=0;i<getSelectSets();i++)
|
for (int i=0;i<getSelectSets();i++)
|
||||||
{
|
{
|
||||||
|
@ -271,7 +265,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
if (sets==null)
|
if (sets==null)
|
||||||
return;
|
return;
|
||||||
SelectSet set=sets[id];
|
SelectSet set=sets[id];
|
||||||
|
|
||||||
Thread.currentThread().setName(name+" Selector"+id);
|
Thread.currentThread().setName(name+" Selector"+id);
|
||||||
if (getSelectorPriorityDelta()!=0)
|
if (getSelectorPriorityDelta()!=0)
|
||||||
Thread.currentThread().setPriority(Thread.currentThread().getPriority()+getSelectorPriorityDelta());
|
Thread.currentThread().setPriority(Thread.currentThread().getPriority()+getSelectorPriorityDelta());
|
||||||
|
@ -362,7 +356,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
LOG.warn(ex+","+channel+","+attachment);
|
LOG.warn(ex+","+channel+","+attachment);
|
||||||
LOG.debug(ex);
|
LOG.debug(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public String dump()
|
public String dump()
|
||||||
{
|
{
|
||||||
|
@ -375,8 +369,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
out.append(String.valueOf(this)).append("\n");
|
out.append(String.valueOf(this)).append("\n");
|
||||||
AggregateLifeCycle.dump(out,indent,TypeUtil.asList(_selectSet));
|
AggregateLifeCycle.dump(out,indent,TypeUtil.asList(_selectSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
|
@ -384,27 +378,19 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
private final int _setID;
|
private final int _setID;
|
||||||
private final Timeout _timeout;
|
private final Timeout _timeout;
|
||||||
|
|
||||||
private final ConcurrentLinkedQueue<Object> _changes = new ConcurrentLinkedQueue<Object>();
|
private final ConcurrentLinkedQueue<Object> _changes = new ConcurrentLinkedQueue<Object>();
|
||||||
|
|
||||||
private volatile Selector _selector;
|
private volatile Selector _selector;
|
||||||
|
|
||||||
private volatile Thread _selecting;
|
private volatile Thread _selecting;
|
||||||
private int _jvmBug;
|
private int _busySelects;
|
||||||
private int _selects;
|
|
||||||
private long _monitorStart;
|
|
||||||
private long _monitorNext;
|
private long _monitorNext;
|
||||||
private boolean _pausing;
|
private boolean _pausing;
|
||||||
private SelectionKey _busyKey;
|
private boolean _paused;
|
||||||
private int _busyKeyCount;
|
|
||||||
private long _log;
|
|
||||||
private int _paused;
|
|
||||||
private int _jvmFix0;
|
|
||||||
private int _jvmFix1;
|
|
||||||
private int _jvmFix2;
|
|
||||||
private volatile long _idleTick;
|
private volatile long _idleTick;
|
||||||
private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>();
|
private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>();
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
SelectSet(int acceptorID) throws Exception
|
SelectSet(int acceptorID) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -416,11 +402,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
// create a selector;
|
// create a selector;
|
||||||
_selector = Selector.open();
|
_selector = Selector.open();
|
||||||
_monitorStart=System.currentTimeMillis();
|
_monitorNext=System.currentTimeMillis()+__MONITOR_PERIOD;
|
||||||
_monitorNext=_monitorStart+__MONITOR_PERIOD;
|
|
||||||
_log=_monitorStart+60000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void addChange(Object change)
|
public void addChange(Object change)
|
||||||
{
|
{
|
||||||
|
@ -429,7 +413,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void addChange(SelectableChannel channel, Object att)
|
public void addChange(SelectableChannel channel, Object att)
|
||||||
{
|
{
|
||||||
if (att==null)
|
if (att==null)
|
||||||
addChange(channel);
|
addChange(channel);
|
||||||
else if (att instanceof EndPoint)
|
else if (att instanceof EndPoint)
|
||||||
|
@ -437,11 +421,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
else
|
else
|
||||||
addChange(new ChannelAndAttachment(channel,att));
|
addChange(new ChannelAndAttachment(channel,att));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Select and dispatch tasks found from changes and the selector.
|
* Select and dispatch tasks found from changes and the selector.
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void doSelect() throws IOException
|
public void doSelect() throws IOException
|
||||||
|
@ -450,6 +434,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
_selecting=Thread.currentThread();
|
_selecting=Thread.currentThread();
|
||||||
final Selector selector=_selector;
|
final Selector selector=_selector;
|
||||||
|
// Stopped concurrently ?
|
||||||
|
if (selector == null)
|
||||||
|
return;
|
||||||
|
|
||||||
// Make any key changes required
|
// Make any key changes required
|
||||||
Object change;
|
Object change;
|
||||||
|
@ -458,7 +445,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
Channel ch=null;
|
Channel ch=null;
|
||||||
SelectionKey key=null;
|
SelectionKey key=null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (change instanceof EndPoint)
|
if (change instanceof EndPoint)
|
||||||
|
@ -475,7 +462,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
final SelectableChannel channel=asc._channel;
|
final SelectableChannel channel=asc._channel;
|
||||||
ch=channel;
|
ch=channel;
|
||||||
final Object att = asc._attachment;
|
final Object att = asc._attachment;
|
||||||
|
|
||||||
if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected())
|
if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected())
|
||||||
{
|
{
|
||||||
key = channel.register(selector,SelectionKey.OP_READ,att);
|
key = channel.register(selector,SelectionKey.OP_READ,att);
|
||||||
|
@ -517,7 +504,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
if (e instanceof ThreadDeath)
|
if (e instanceof ThreadDeath)
|
||||||
throw (ThreadDeath)e;
|
throw (ThreadDeath)e;
|
||||||
|
|
||||||
if (isRunning())
|
if (isRunning())
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
else
|
else
|
||||||
|
@ -525,7 +512,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ch.close();
|
if (ch!=null)
|
||||||
|
ch.close();
|
||||||
}
|
}
|
||||||
catch(IOException e2)
|
catch(IOException e2)
|
||||||
{
|
{
|
||||||
|
@ -537,10 +525,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
// Do and instant select to see if any connections can be handled.
|
// Do and instant select to see if any connections can be handled.
|
||||||
int selected=selector.selectNow();
|
int selected=selector.selectNow();
|
||||||
_selects++;
|
|
||||||
|
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
|
|
||||||
// if no immediate things to do
|
// if no immediate things to do
|
||||||
if (selected==0 && selector.selectedKeys().isEmpty())
|
if (selected==0 && selector.selectedKeys().isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -562,7 +549,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
_timeout.setNow(now);
|
_timeout.setNow(now);
|
||||||
long to_next_timeout=_timeout.getTimeToNext();
|
long to_next_timeout=_timeout.getTimeToNext();
|
||||||
|
|
||||||
long wait = _changes.size()==0?__IDLE_TICK:0L;
|
long wait = _changes.size()==0?__IDLE_TICK:0L;
|
||||||
if (wait > 0 && to_next_timeout >= 0 && wait > to_next_timeout)
|
if (wait > 0 && to_next_timeout >= 0 && wait > to_next_timeout)
|
||||||
wait = to_next_timeout;
|
wait = to_next_timeout;
|
||||||
|
|
||||||
|
@ -571,24 +558,48 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
long before=now;
|
long before=now;
|
||||||
selected=selector.select(wait);
|
selected=selector.select(wait);
|
||||||
_selects++;
|
|
||||||
now = System.currentTimeMillis();
|
now = System.currentTimeMillis();
|
||||||
_timeout.setNow(now);
|
_timeout.setNow(now);
|
||||||
|
|
||||||
if (__JVMBUG_THRESHHOLD>0)
|
// If we are monitoring for busy selector
|
||||||
checkJvmBugs(before, now, wait, selected);
|
// and this select did not wait more than 1ms
|
||||||
|
if (__MONITOR_PERIOD>0 && now-before <=1)
|
||||||
|
{
|
||||||
|
// count this as a busy select and if there have been too many this monitor cycle
|
||||||
|
if (++_busySelects>__MAX_SELECTS)
|
||||||
|
{
|
||||||
|
// Start injecting pauses
|
||||||
|
_pausing=true;
|
||||||
|
|
||||||
|
// if this is the first pause
|
||||||
|
if (!_paused)
|
||||||
|
{
|
||||||
|
// Log and dump some status
|
||||||
|
_paused=true;
|
||||||
|
LOG.warn("Selector {} is too busy, pausing!",this);
|
||||||
|
final SelectSet set = this;
|
||||||
|
SelectorManager.this.dispatch(
|
||||||
|
new Runnable(){
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
System.err.println(set+":\n"+set.dump());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// have we been destroyed while sleeping
|
// have we been destroyed while sleeping
|
||||||
if (_selector==null || !selector.isOpen())
|
if (_selector==null || !selector.isOpen())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Look for things to do
|
// Look for things to do
|
||||||
for (SelectionKey key: selector.selectedKeys())
|
for (SelectionKey key: selector.selectedKeys())
|
||||||
{
|
{
|
||||||
SocketChannel channel=null;
|
SocketChannel channel=null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!key.isValid())
|
if (!key.isValid())
|
||||||
|
@ -641,7 +652,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
SelectChannelEndPoint endpoint = createEndPoint(channel,key);
|
SelectChannelEndPoint endpoint = createEndPoint(channel,key);
|
||||||
key.attach(endpoint);
|
key.attach(endpoint);
|
||||||
if (key.isReadable())
|
if (key.isReadable())
|
||||||
endpoint.schedule();
|
endpoint.schedule();
|
||||||
}
|
}
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
@ -665,15 +676,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
LOG.debug(e2);
|
LOG.debug(e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())
|
if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())
|
||||||
key.cancel();
|
key.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything always handled
|
// Everything always handled
|
||||||
selector.selectedKeys().clear();
|
selector.selectedKeys().clear();
|
||||||
|
|
||||||
now=System.currentTimeMillis();
|
now=System.currentTimeMillis();
|
||||||
_timeout.setNow(now);
|
_timeout.setNow(now);
|
||||||
Task task = _timeout.expired();
|
Task task = _timeout.expired();
|
||||||
|
@ -688,11 +699,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
if (now-_idleTick>__IDLE_TICK)
|
if (now-_idleTick>__IDLE_TICK)
|
||||||
{
|
{
|
||||||
_idleTick=now;
|
_idleTick=now;
|
||||||
|
|
||||||
final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
|
final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
|
||||||
?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
|
?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
|
||||||
:now;
|
:now;
|
||||||
|
|
||||||
dispatch(new Runnable()
|
dispatch(new Runnable()
|
||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
|
@ -703,6 +714,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset busy select monitor counts
|
||||||
|
if (__MONITOR_PERIOD>0 && now>_monitorNext)
|
||||||
|
{
|
||||||
|
_busySelects=0;
|
||||||
|
_pausing=false;
|
||||||
|
_monitorNext=now+__MONITOR_PERIOD;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ClosedSelectorException e)
|
catch (ClosedSelectorException e)
|
||||||
|
@ -721,130 +742,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
_selecting=null;
|
_selecting=null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void checkJvmBugs(long before, long now, long wait, int selected)
|
private void renewSelector()
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
Selector selector = _selector;
|
|
||||||
if (selector==null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Look for JVM bugs over a monitor period.
|
|
||||||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933
|
|
||||||
// http://bugs.sun.com/view_bug.do?bug_id=6693490
|
|
||||||
if (now>_monitorNext)
|
|
||||||
{
|
|
||||||
_selects=(int)(_selects*__MONITOR_PERIOD/(now-_monitorStart));
|
|
||||||
_pausing=_selects>__MAX_SELECTS;
|
|
||||||
if (_pausing)
|
|
||||||
_paused++;
|
|
||||||
|
|
||||||
_selects=0;
|
|
||||||
_jvmBug=0;
|
|
||||||
_monitorStart=now;
|
|
||||||
_monitorNext=now+__MONITOR_PERIOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now>_log)
|
|
||||||
{
|
|
||||||
if (_paused>0)
|
|
||||||
LOG.debug(this+" Busy selector - injecting delay "+_paused+" times");
|
|
||||||
|
|
||||||
if (_jvmFix2>0)
|
|
||||||
LOG.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times");
|
|
||||||
|
|
||||||
if (_jvmFix1>0)
|
|
||||||
LOG.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times");
|
|
||||||
|
|
||||||
else if(LOG.isDebugEnabled() && _jvmFix0>0)
|
|
||||||
LOG.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times");
|
|
||||||
_paused=0;
|
|
||||||
_jvmFix2=0;
|
|
||||||
_jvmFix1=0;
|
|
||||||
_jvmFix0=0;
|
|
||||||
_log=now+60000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we see signature of possible JVM bug, increment count.
|
|
||||||
if (selected==0 && wait>10 && (now-before)<(wait/2))
|
|
||||||
{
|
|
||||||
// Increment bug count and try a work around
|
|
||||||
_jvmBug++;
|
|
||||||
if (_jvmBug>(__JVMBUG_THRESHHOLD))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_jvmBug==__JVMBUG_THRESHHOLD+1)
|
|
||||||
_jvmFix2++;
|
|
||||||
|
|
||||||
Thread.sleep(__BUSY_PAUSE); // pause to avoid busy loop
|
|
||||||
}
|
|
||||||
catch(InterruptedException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_jvmBug==__JVMBUG_THRESHHOLD)
|
|
||||||
{
|
|
||||||
renewSelector();
|
|
||||||
}
|
|
||||||
else if (_jvmBug%32==31) // heuristic attempt to cancel key 31,63,95,... loops
|
|
||||||
{
|
|
||||||
// Cancel keys with 0 interested ops
|
|
||||||
int cancelled=0;
|
|
||||||
for (SelectionKey k: selector.keys())
|
|
||||||
{
|
|
||||||
if (k.isValid()&&k.interestOps()==0)
|
|
||||||
{
|
|
||||||
k.cancel();
|
|
||||||
cancelled++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cancelled>0)
|
|
||||||
_jvmFix0++;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__BUSY_KEY>0 && selected==1 && _selects>__MAX_SELECTS)
|
|
||||||
{
|
|
||||||
// Look for busy key
|
|
||||||
SelectionKey busy = selector.selectedKeys().iterator().next();
|
|
||||||
if (busy==_busyKey)
|
|
||||||
{
|
|
||||||
if (++_busyKeyCount>__BUSY_KEY && !(busy.channel() instanceof ServerSocketChannel))
|
|
||||||
{
|
|
||||||
final SelectChannelEndPoint endpoint = (SelectChannelEndPoint)busy.attachment();
|
|
||||||
LOG.warn("Busy Key "+busy.channel()+" "+endpoint);
|
|
||||||
busy.cancel();
|
|
||||||
if (endpoint!=null)
|
|
||||||
{
|
|
||||||
dispatch(new Runnable()
|
|
||||||
{
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
endpoint.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_busyKeyCount=0;
|
|
||||||
_busyKey=busy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private void renewSelector()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -876,7 +777,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
throw new RuntimeException("recreating selector",e);
|
throw new RuntimeException("recreating selector",e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public SelectorManager getManager()
|
public SelectorManager getManager()
|
||||||
{
|
{
|
||||||
|
@ -891,9 +792,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @param task The task to timeout. If it implements Runnable, then
|
* @param task The task to timeout. If it implements Runnable, then
|
||||||
* expired will be called from a dispatched thread.
|
* expired will be called from a dispatched thread.
|
||||||
*
|
*
|
||||||
* @param timeoutMs
|
* @param timeoutMs
|
||||||
*/
|
*/
|
||||||
public void scheduleTimeout(Timeout.Task task, long timeoutMs)
|
public void scheduleTimeout(Timeout.Task task, long timeoutMs)
|
||||||
|
@ -902,7 +803,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
throw new IllegalArgumentException("!Runnable");
|
throw new IllegalArgumentException("!Runnable");
|
||||||
_timeout.schedule(task, timeoutMs);
|
_timeout.schedule(task, timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void cancelTimeout(Timeout.Task task)
|
public void cancelTimeout(Timeout.Task task)
|
||||||
{
|
{
|
||||||
|
@ -927,23 +828,24 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
renewSelector();
|
renewSelector();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
renewSelector();
|
renewSelector();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException
|
private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException
|
||||||
{
|
{
|
||||||
SelectChannelEndPoint endp = newEndPoint(channel,this,sKey);
|
SelectChannelEndPoint endp = newEndPoint(channel,this,sKey);
|
||||||
endPointOpened(endp);
|
endPointOpened(endp);
|
||||||
_endPoints.put(endp,this);
|
_endPoints.put(endp,this);
|
||||||
return endp;
|
return endp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void destroyEndPoint(SelectChannelEndPoint endp)
|
public void destroyEndPoint(SelectChannelEndPoint endp)
|
||||||
{
|
{
|
||||||
|
LOG.debug("destroyEndPoint {}",endp);
|
||||||
_endPoints.remove(endp);
|
_endPoints.remove(endp);
|
||||||
endPointClosed(endp);
|
endPointClosed(endp);
|
||||||
}
|
}
|
||||||
|
@ -953,11 +855,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
return _selector;
|
return _selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
void stop() throws Exception
|
void stop() throws Exception
|
||||||
{
|
{
|
||||||
// Spin for a while waiting for selector to complete
|
// Spin for a while waiting for selector to complete
|
||||||
// to avoid unneccessary closed channel exceptions
|
// to avoid unneccessary closed channel exceptions
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -994,8 +896,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_timeout.cancelAll();
|
_timeout.cancelAll();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1006,7 +908,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOG.ignore(e);
|
LOG.ignore(e);
|
||||||
}
|
}
|
||||||
_selector=null;
|
_selector=null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1021,9 +923,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
public void dump(Appendable out, String indent) throws IOException
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
{
|
{
|
||||||
out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_setID)).append("\n");
|
out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_setID)).append("\n");
|
||||||
|
|
||||||
Thread selecting = _selecting;
|
Thread selecting = _selecting;
|
||||||
|
|
||||||
Object where = "not selecting";
|
Object where = "not selecting";
|
||||||
StackTraceElement[] trace =selecting==null?null:selecting.getStackTrace();
|
StackTraceElement[] trace =selecting==null?null:selecting.getStackTrace();
|
||||||
if (trace!=null)
|
if (trace!=null)
|
||||||
|
@ -1037,28 +939,32 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
}
|
}
|
||||||
|
|
||||||
Selector selector=_selector;
|
Selector selector=_selector;
|
||||||
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
|
if (selector!=null)
|
||||||
dump.add(where);
|
{
|
||||||
|
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
dump.add(where);
|
||||||
|
|
||||||
addChange(new Runnable(){
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
public void run()
|
|
||||||
|
addChange(new ChangeTask()
|
||||||
{
|
{
|
||||||
dumpKeyState(dump);
|
public void run()
|
||||||
latch.countDown();
|
{
|
||||||
|
dumpKeyState(dump);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
latch.await(5,TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
});
|
catch(InterruptedException e)
|
||||||
|
{
|
||||||
try
|
LOG.ignore(e);
|
||||||
{
|
}
|
||||||
latch.await(5,TimeUnit.SECONDS);
|
AggregateLifeCycle.dump(out,indent,dump);
|
||||||
}
|
}
|
||||||
catch(InterruptedException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
AggregateLifeCycle.dump(out,indent,dump);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -1081,7 +987,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
final SelectableChannel _channel;
|
final SelectableChannel _channel;
|
||||||
final Object _attachment;
|
final Object _attachment;
|
||||||
|
|
||||||
public ChannelAndAttachment(SelectableChannel channel, Object attachment)
|
public ChannelAndAttachment(SelectableChannel channel, Object attachment)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -1101,12 +1007,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
||||||
{
|
{
|
||||||
_deferringInterestedOps0 = deferringInterestedOps0;
|
_deferringInterestedOps0 = deferringInterestedOps0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private interface ChangeTask extends Runnable
|
private interface ChangeTask extends Runnable
|
||||||
{}
|
{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,69 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 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.jndi;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.naming.Binding;
|
||||||
|
import javax.naming.NamingEnumeration;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
|
||||||
|
/** BindingEnumeration
|
||||||
|
* <p>Implementation of NamingEnumeration
|
||||||
|
*
|
||||||
|
* <p><h4>Notes</h4>
|
||||||
|
* <p>Used to return results of Context.listBindings();
|
||||||
|
*
|
||||||
|
* <p><h4>Usage</h4>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BindingEnumeration implements NamingEnumeration<Binding>
|
||||||
|
{
|
||||||
|
Iterator<Binding> _delegate;
|
||||||
|
|
||||||
|
public BindingEnumeration (Iterator<Binding> e)
|
||||||
|
{
|
||||||
|
_delegate = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMore ()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
return _delegate.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Binding next()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
Binding b = (Binding)_delegate.next();
|
||||||
|
return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMoreElements()
|
||||||
|
{
|
||||||
|
return _delegate.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Binding nextElement()
|
||||||
|
{
|
||||||
|
Binding b = (Binding)_delegate.next();
|
||||||
|
return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 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.jndi;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.naming.Binding;
|
||||||
|
import javax.naming.NameClassPair;
|
||||||
|
import javax.naming.NamingEnumeration;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
|
||||||
|
/** NameEnumeration
|
||||||
|
* <p>Implementation of NamingEnumeration interface.
|
||||||
|
*
|
||||||
|
* <p><h4>Notes</h4>
|
||||||
|
* <p>Used for returning results of Context.list();
|
||||||
|
*
|
||||||
|
* <p><h4>Usage</h4>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NameEnumeration implements NamingEnumeration<NameClassPair>
|
||||||
|
{
|
||||||
|
Iterator<Binding> _delegate;
|
||||||
|
|
||||||
|
public NameEnumeration (Iterator<Binding> e)
|
||||||
|
{
|
||||||
|
_delegate = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMore ()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
return _delegate.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameClassPair next()
|
||||||
|
throws NamingException
|
||||||
|
{
|
||||||
|
Binding b = _delegate.next();
|
||||||
|
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMoreElements()
|
||||||
|
{
|
||||||
|
return _delegate.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameClassPair nextElement()
|
||||||
|
{
|
||||||
|
Binding b = _delegate.next();
|
||||||
|
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -31,7 +30,6 @@ import javax.naming.InitialContext;
|
||||||
import javax.naming.LinkRef;
|
import javax.naming.LinkRef;
|
||||||
import javax.naming.Name;
|
import javax.naming.Name;
|
||||||
import javax.naming.NameAlreadyBoundException;
|
import javax.naming.NameAlreadyBoundException;
|
||||||
import javax.naming.NameClassPair;
|
|
||||||
import javax.naming.NameNotFoundException;
|
import javax.naming.NameNotFoundException;
|
||||||
import javax.naming.NameParser;
|
import javax.naming.NameParser;
|
||||||
import javax.naming.NamingEnumeration;
|
import javax.naming.NamingEnumeration;
|
||||||
|
@ -53,17 +51,8 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* <p><h4>Notes</h4>
|
* <p><h4>Notes</h4>
|
||||||
* <p>All Names are expected to be Compound, not Composite.
|
* <p>All Names are expected to be Compound, not Composite.
|
||||||
*
|
*
|
||||||
* <p><h4>Usage</h4>
|
*
|
||||||
* <pre>
|
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
public class NamingContext implements Context, Cloneable, Dumpable
|
public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
{
|
{
|
||||||
private final static Logger __log=NamingUtil.__log;
|
private final static Logger __log=NamingUtil.__log;
|
||||||
|
@ -101,123 +90,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
void unbind(NamingContext ctx, Binding binding);
|
void unbind(NamingContext ctx, Binding binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
|
||||||
/** NameEnumeration
|
|
||||||
* <p>Implementation of NamingEnumeration interface.
|
|
||||||
*
|
|
||||||
* <p><h4>Notes</h4>
|
|
||||||
* <p>Used for returning results of Context.list();
|
|
||||||
*
|
|
||||||
* <p><h4>Usage</h4>
|
|
||||||
* <pre>
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class NameEnumeration implements NamingEnumeration<NameClassPair>
|
|
||||||
{
|
|
||||||
Iterator<Binding> _delegate;
|
|
||||||
|
|
||||||
public NameEnumeration (Iterator<Binding> e)
|
|
||||||
{
|
|
||||||
_delegate = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMore ()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
return _delegate.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameClassPair next()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
Binding b = _delegate.next();
|
|
||||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return _delegate.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameClassPair nextElement()
|
|
||||||
{
|
|
||||||
Binding b = _delegate.next();
|
|
||||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
|
||||||
/** BindingEnumeration
|
|
||||||
* <p>Implementation of NamingEnumeration
|
|
||||||
*
|
|
||||||
* <p><h4>Notes</h4>
|
|
||||||
* <p>Used to return results of Context.listBindings();
|
|
||||||
*
|
|
||||||
* <p><h4>Usage</h4>
|
|
||||||
* <pre>
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class BindingEnumeration implements NamingEnumeration<Binding>
|
|
||||||
{
|
|
||||||
Iterator<Binding> _delegate;
|
|
||||||
|
|
||||||
public BindingEnumeration (Iterator<Binding> e)
|
|
||||||
{
|
|
||||||
_delegate = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMore ()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
return _delegate.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Binding next()
|
|
||||||
throws NamingException
|
|
||||||
{
|
|
||||||
Binding b = (Binding)_delegate.next();
|
|
||||||
return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return _delegate.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Binding nextElement()
|
|
||||||
{
|
|
||||||
Binding b = (Binding)_delegate.next();
|
|
||||||
return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -240,26 +112,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
|
||||||
/**
|
|
||||||
* Creates a new <code>NamingContext</code> instance.
|
|
||||||
*
|
|
||||||
* @param env a <code>Hashtable</code> value
|
|
||||||
*/
|
|
||||||
public NamingContext (Hashtable<String,Object> env)
|
|
||||||
{
|
|
||||||
if (env != null)
|
|
||||||
_env.putAll(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public NamingContext ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
|
@ -312,8 +164,24 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
_parser = parser;
|
_parser = parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setEnv (Hashtable<String,Object> env)
|
||||||
|
{
|
||||||
|
_env.clear();
|
||||||
|
_env.putAll(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String,Binding> getBindings ()
|
||||||
|
{
|
||||||
|
return _bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBindings(Map<String,Binding> bindings)
|
||||||
|
{
|
||||||
|
_bindings = bindings;
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Bind a name to an object
|
* Bind a name to an object
|
||||||
|
@ -435,8 +303,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
ne.setRemainingName(name);
|
ne.setRemainingName(name);
|
||||||
throw ne;
|
throw ne;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Name cname = toCanonicalName (name);
|
Name cname = toCanonicalName (name);
|
||||||
|
|
||||||
|
@ -521,7 +387,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Not supported
|
*
|
||||||
*
|
*
|
||||||
* @param name name of subcontext to remove
|
* @param name name of subcontext to remove
|
||||||
* @exception NamingException if an error occurs
|
* @exception NamingException if an error occurs
|
||||||
|
@ -536,7 +402,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Not supported
|
*
|
||||||
*
|
*
|
||||||
* @param name name of subcontext to remove
|
* @param name name of subcontext to remove
|
||||||
* @exception NamingException if an error occurs
|
* @exception NamingException if an error occurs
|
||||||
|
@ -1128,7 +994,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
|
|
||||||
ctx = binding.getObject();
|
ctx = binding.getObject();
|
||||||
|
|
||||||
|
|
||||||
if (ctx instanceof Reference)
|
if (ctx instanceof Reference)
|
||||||
{
|
{
|
||||||
//deference the object
|
//deference the object
|
||||||
|
@ -1154,8 +1019,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
|
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
|
@ -1182,11 +1046,11 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
* @param newName a <code>Name</code> value
|
* @param newName a <code>Name</code> value
|
||||||
* @exception NamingException if an error occurs
|
* @exception NamingException if an error occurs
|
||||||
*/ public void rename(String oldName,
|
*/ public void rename(String oldName,
|
||||||
String newName)
|
String newName)
|
||||||
throws NamingException
|
throws NamingException
|
||||||
{
|
{
|
||||||
throw new OperationNotSupportedException();
|
throw new OperationNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1247,9 +1111,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
*/
|
*/
|
||||||
public void close ()
|
public void close ()
|
||||||
throws NamingException
|
throws NamingException
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1362,7 +1224,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
* @param name a <code>Name</code> value
|
* @param name a <code>Name</code> value
|
||||||
* @param obj an <code>Object</code> value
|
* @param obj an <code>Object</code> value
|
||||||
*/
|
*/
|
||||||
protected void addBinding (Name name, Object obj) throws NameAlreadyBoundException
|
public void addBinding (Name name, Object obj) throws NameAlreadyBoundException
|
||||||
{
|
{
|
||||||
String key = name.toString();
|
String key = name.toString();
|
||||||
Binding binding=new Binding (key, obj);
|
Binding binding=new Binding (key, obj);
|
||||||
|
@ -1394,7 +1256,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
* @param name a <code>Name</code> value
|
* @param name a <code>Name</code> value
|
||||||
* @return a <code>Binding</code> value
|
* @return a <code>Binding</code> value
|
||||||
*/
|
*/
|
||||||
protected Binding getBinding (Name name)
|
public Binding getBinding (Name name)
|
||||||
{
|
{
|
||||||
return (Binding) _bindings.get(name.toString());
|
return (Binding) _bindings.get(name.toString());
|
||||||
}
|
}
|
||||||
|
@ -1407,13 +1269,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
* @param name as a String
|
* @param name as a String
|
||||||
* @return null or the Binding
|
* @return null or the Binding
|
||||||
*/
|
*/
|
||||||
protected Binding getBinding (String name)
|
public Binding getBinding (String name)
|
||||||
{
|
{
|
||||||
return (Binding) _bindings.get(name);
|
return (Binding) _bindings.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------*/
|
/*------------------------------------------------*/
|
||||||
protected void removeBinding (Name name)
|
public void removeBinding (Name name)
|
||||||
{
|
{
|
||||||
String key = name.toString();
|
String key = name.toString();
|
||||||
if (__log.isDebugEnabled())
|
if (__log.isDebugEnabled())
|
||||||
|
@ -1455,7 +1317,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private boolean isLocked()
|
public boolean isLocked()
|
||||||
{
|
{
|
||||||
if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null))
|
if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -67,8 +67,7 @@ public class javaRootURLContext implements Context
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
__javaNameParser = new javaNameParser();
|
__javaNameParser = new javaNameParser();
|
||||||
__nameRoot = new NamingContext();
|
__nameRoot = new NamingContext(null,null,null,__javaNameParser);
|
||||||
__nameRoot.setNameParser(__javaNameParser);
|
|
||||||
|
|
||||||
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());
|
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,11 +12,19 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
package org.eclipse.jetty.jndi.java;
|
package org.eclipse.jetty.jndi.java;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
import javax.naming.Context;
|
import javax.naming.Context;
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
import javax.naming.Name;
|
import javax.naming.Name;
|
||||||
import javax.naming.NameNotFoundException;
|
import javax.naming.NameNotFoundException;
|
||||||
import javax.naming.NameParser;
|
import javax.naming.NameParser;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.RefAddr;
|
||||||
|
import javax.naming.Reference;
|
||||||
|
import javax.naming.Referenceable;
|
||||||
|
import javax.naming.StringRefAddr;
|
||||||
|
import javax.naming.spi.ObjectFactory;
|
||||||
|
|
||||||
import org.eclipse.jetty.jndi.NamingUtil;
|
import org.eclipse.jetty.jndi.NamingUtil;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -31,13 +39,152 @@ import static org.junit.Assert.fail;
|
||||||
*/
|
*/
|
||||||
public class TestLocalJNDI
|
public class TestLocalJNDI
|
||||||
{
|
{
|
||||||
|
public static class FruitFactory implements ObjectFactory
|
||||||
|
{
|
||||||
|
public FruitFactory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!env.containsKey("flavour"))
|
||||||
|
throw new Exception ("No flavour!");
|
||||||
|
|
||||||
|
if (obj instanceof Reference)
|
||||||
|
{
|
||||||
|
Reference ref = (Reference)obj;
|
||||||
|
if (ref.getClassName().equals(Fruit.class.getName()))
|
||||||
|
{
|
||||||
|
RefAddr addr = ref.get("fruit");
|
||||||
|
if (addr != null)
|
||||||
|
{
|
||||||
|
return new Fruit((String)addr.getContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Fruit implements Referenceable
|
||||||
|
{
|
||||||
|
String fruit;
|
||||||
|
|
||||||
|
public Fruit(String f)
|
||||||
|
{
|
||||||
|
fruit = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reference getReference() throws NamingException
|
||||||
|
{
|
||||||
|
return new Reference(
|
||||||
|
Fruit.class.getName(),
|
||||||
|
new StringRefAddr("fruit", fruit),
|
||||||
|
FruitFactory.class.getName(),
|
||||||
|
null); // Factory location
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return fruit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception
|
public void tearDown() throws Exception
|
||||||
{
|
{
|
||||||
InitialContext ic = new InitialContext();
|
InitialContext ic = new InitialContext();
|
||||||
ic.destroySubcontext("a");
|
ic.destroySubcontext("a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalReferenceable() throws Exception
|
||||||
|
{
|
||||||
|
Hashtable<String,String> env1 = new Hashtable<String,String>();
|
||||||
|
env1.put("flavour", "orange");
|
||||||
|
InitialContext ic1 = new InitialContext(env1);
|
||||||
|
|
||||||
|
ic1.bind("valencia", new Fruit("orange"));
|
||||||
|
|
||||||
|
Object o = ic1.lookup("valencia");
|
||||||
|
|
||||||
|
Hashtable<String,String> env2 = new Hashtable<String,String>();
|
||||||
|
InitialContext ic2 = new InitialContext(env2);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
o = ic2.lookup("valencia");
|
||||||
|
fail("Constructed object from reference without correct environment");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertEquals("No flavour!", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalEnvironment() throws Exception
|
||||||
|
{
|
||||||
|
Hashtable<String,String> env1 = new Hashtable<String,String>();
|
||||||
|
env1.put("make", "holden");
|
||||||
|
env1.put("model", "commodore");
|
||||||
|
|
||||||
|
Object car1 = new Object();
|
||||||
|
|
||||||
|
InitialContext ic = new InitialContext(env1);
|
||||||
|
ic.bind("car1", car1);
|
||||||
|
assertNotNull(ic.lookup("car1"));
|
||||||
|
assertEquals(car1, ic.lookup("car1"));
|
||||||
|
|
||||||
|
Context carz = ic.createSubcontext("carz");
|
||||||
|
assertNotNull(carz);
|
||||||
|
Hashtable ht = carz.getEnvironment();
|
||||||
|
assertNotNull(ht);
|
||||||
|
assertEquals("holden", ht.get("make"));
|
||||||
|
assertEquals("commodore", ht.get("model"));
|
||||||
|
|
||||||
|
Hashtable<String,String> env2 = new Hashtable<String,String>();
|
||||||
|
env2.put("flavour", "strawberry");
|
||||||
|
InitialContext ic2 = new InitialContext(env2);
|
||||||
|
assertEquals(car1, ic2.lookup("car1"));
|
||||||
|
Context c = (Context)ic2.lookup("carz");
|
||||||
|
assertNotNull(c);
|
||||||
|
ht = c.getEnvironment();
|
||||||
|
assertEquals("holden", ht.get("make"));
|
||||||
|
assertEquals("commodore", ht.get("model"));
|
||||||
|
|
||||||
|
Context icecreamz = ic2.createSubcontext("icecreamz");
|
||||||
|
ht = icecreamz.getEnvironment();
|
||||||
|
assertNotNull(ht);
|
||||||
|
assertEquals("strawberry", ht.get("flavour"));
|
||||||
|
|
||||||
|
Context hatchbackz = ic2.createSubcontext("carz/hatchbackz");
|
||||||
|
assertNotNull(hatchbackz);
|
||||||
|
ht = hatchbackz.getEnvironment();
|
||||||
|
assertNotNull(ht);
|
||||||
|
assertEquals("holden", ht.get("make"));
|
||||||
|
assertEquals("commodore", ht.get("model"));
|
||||||
|
assertEquals(null, ht.get("flavour"));
|
||||||
|
|
||||||
|
c = (Context)ic.lookup("carz/hatchbackz");
|
||||||
|
assertNotNull(c);
|
||||||
|
assertEquals(hatchbackz, c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocal () throws Exception
|
public void testLocal () throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,7 +84,8 @@ public class NestedConnection extends HttpConnection
|
||||||
{
|
{
|
||||||
getServer().handle(this);
|
getServer().handle(this);
|
||||||
completeResponse();
|
completeResponse();
|
||||||
_generator.flushBuffer();
|
while (!_generator.isComplete() && _endp.isOpen())
|
||||||
|
_generator.flushBuffer();
|
||||||
_endp.flush();
|
_endp.flush();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
|
|
||||||
public void addContent(Buffer content, boolean last) throws IOException
|
public void addContent(Buffer content, boolean last) throws IOException
|
||||||
{
|
{
|
||||||
// LOG.debug("addContent {} {}",content.length(),last);
|
LOG.debug("addContent {} {}",content.length(),last);
|
||||||
if (_noContent)
|
if (_noContent)
|
||||||
{
|
{
|
||||||
content.clear();
|
content.clear();
|
||||||
|
@ -70,7 +70,6 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
// Handle any unfinished business?
|
// Handle any unfinished business?
|
||||||
if (_content != null && _content.length() > 0)
|
if (_content != null && _content.length() > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
if (_content != null && _content.length() > 0)
|
if (_content != null && _content.length() > 0)
|
||||||
throw new IllegalStateException("FULL");
|
throw new IllegalStateException("FULL");
|
||||||
|
@ -86,20 +85,22 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
content.clear();
|
content.clear();
|
||||||
_content = null;
|
_content = null;
|
||||||
}
|
}
|
||||||
else
|
else if (!last || _buffer!=null)
|
||||||
{
|
{
|
||||||
// Yes - so we better check we have a buffer
|
// Yes - so we better check we have a buffer
|
||||||
initContent();
|
initBuffer();
|
||||||
// Copy _content to buffer;
|
// Copy _content to buffer;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
len = _buffer.put(_content);
|
len = _buffer.put(_content);
|
||||||
|
|
||||||
// make sure there is space for a trailing null
|
// make sure there is space for a trailing null (???)
|
||||||
if (len > 0 && _buffer.space() == 0)
|
if (len > 0 && _buffer.space() == 0)
|
||||||
{
|
{
|
||||||
len--;
|
len--;
|
||||||
_buffer.setPutIndex(_buffer.putIndex() - 1);
|
_buffer.setPutIndex(_buffer.putIndex() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.debug("copied {} to buffer",len);
|
||||||
|
|
||||||
_content.skip(len);
|
_content.skip(len);
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we better check we have a buffer
|
// we better check we have a buffer
|
||||||
initContent();
|
initBuffer();
|
||||||
|
|
||||||
// Copy _content to buffer;
|
// Copy _content to buffer;
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private void initContent() throws IOException
|
private void initBuffer() throws IOException
|
||||||
{
|
{
|
||||||
if (_buffer == null)
|
if (_buffer == null)
|
||||||
{
|
{
|
||||||
|
@ -176,7 +177,7 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
@Override
|
@Override
|
||||||
public int prepareUncheckedAddContent() throws IOException
|
public int prepareUncheckedAddContent() throws IOException
|
||||||
{
|
{
|
||||||
initContent();
|
initBuffer();
|
||||||
return _buffer.space();
|
return _buffer.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,6 +230,26 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
_state = STATE_CONTENT;
|
_state = STATE_CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* Complete the message.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void complete() throws IOException
|
||||||
|
{
|
||||||
|
if (_state == STATE_END)
|
||||||
|
return;
|
||||||
|
|
||||||
|
super.complete();
|
||||||
|
|
||||||
|
if (_state < STATE_FLUSHING)
|
||||||
|
_state = STATE_FLUSHING;
|
||||||
|
|
||||||
|
flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public long flushBuffer() throws IOException
|
public long flushBuffer() throws IOException
|
||||||
|
@ -236,23 +257,44 @@ public class NestedGenerator extends AbstractGenerator
|
||||||
if (_state == STATE_HEADER)
|
if (_state == STATE_HEADER)
|
||||||
throw new IllegalStateException("State==HEADER");
|
throw new IllegalStateException("State==HEADER");
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
|
||||||
{
|
|
||||||
initContent();
|
|
||||||
_buffer.put(_content);
|
|
||||||
_content.clear();
|
|
||||||
_content = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_buffer==null)
|
if (_buffer==null)
|
||||||
return 0;
|
{
|
||||||
|
|
||||||
|
if (_content!=null && _content.length()>0)
|
||||||
|
{
|
||||||
|
// flush content directly
|
||||||
|
len = _endp.flush(_content);
|
||||||
|
if (len>0)
|
||||||
|
_content.skip(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_buffer.length()==0 && _content!=null && _content.length()>0)
|
||||||
|
{
|
||||||
|
// Copy content to buffer
|
||||||
|
_content.skip(_buffer.put(_content));
|
||||||
|
}
|
||||||
|
|
||||||
|
int size=_buffer.length();
|
||||||
|
len =_endp.flush(_buffer);
|
||||||
|
LOG.debug("flushBuffer {} of {}",len,size);
|
||||||
|
if (len>0)
|
||||||
|
_buffer.skip(len);
|
||||||
|
}
|
||||||
|
|
||||||
int size=_buffer.length();
|
if (_content!=null && _content.length()==0)
|
||||||
int len = _buffer==null?0:_endp.flush(_buffer);
|
_content=null;
|
||||||
LOG.debug("flushBuffer {} of {}",len,size);
|
if (_buffer!=null && _buffer.length()==0 && _content==null)
|
||||||
if (len>0)
|
{
|
||||||
_buffer.skip(len);
|
_buffers.returnBuffer(_buffer);
|
||||||
|
_buffer=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state==STATE_FLUSHING && _buffer==null && _content==null)
|
||||||
|
_state=STATE_END;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -428,7 +428,6 @@ public class MongoSessionManager extends NoSqlSessionManager
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
bout.reset();
|
|
||||||
out.reset();
|
out.reset();
|
||||||
out.writeUnshared(value);
|
out.writeUnshared(value);
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 2010-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.osgi.servletbridge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.equinox.servletbridge.BridgeServlet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the BridgeServlet to report on whether equinox is actually started or not
|
||||||
|
* in case it is started asynchroneously.
|
||||||
|
*
|
||||||
|
* @author hmalphettes
|
||||||
|
*/
|
||||||
|
public class BridgeServletExtended extends BridgeServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS != null
|
||||||
|
&& req.getMethod().equals("GET")) {
|
||||||
|
if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS) {
|
||||||
|
resp.getWriter().append("Equinox is currently starting...\n");
|
||||||
|
return;
|
||||||
|
} else if (FrameworkLauncherExtended.ASYNCH_START_FAILURE != null) {
|
||||||
|
resp.getWriter().append("Equinox failed to start:\n");
|
||||||
|
FrameworkLauncherExtended.ASYNCH_START_FAILURE.printStackTrace(resp.getWriter());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.service(req, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,146 +13,114 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.plus.jaas.spi;
|
package org.eclipse.jetty.plus.jaas.spi;
|
||||||
|
|
||||||
import java.io.File;
|
import java.security.Principal;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.security.Credential;
|
import org.eclipse.jetty.http.security.Credential;
|
||||||
|
import org.eclipse.jetty.security.PropertyUserStore;
|
||||||
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PropertyFileLoginModule
|
* PropertyFileLoginModule
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PropertyFileLoginModule extends AbstractLoginModule
|
public class PropertyFileLoginModule extends AbstractLoginModule
|
||||||
{
|
{
|
||||||
|
public static final String DEFAULT_FILENAME = "realm.properties";
|
||||||
|
|
||||||
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
|
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
|
||||||
|
|
||||||
public static final String DEFAULT_FILENAME = "realm.properties";
|
private static Map<String, PropertyUserStore> _propertyUserStores = new HashMap<String, PropertyUserStore>();
|
||||||
public static final Map<String, Map<String, UserInfo>> fileMap = new HashMap<String, Map<String, UserInfo>>();
|
|
||||||
|
|
||||||
private String propertyFileName;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
private int _refreshInterval = 0;
|
||||||
|
private String _filename = DEFAULT_FILENAME;
|
||||||
|
|
||||||
|
/**
|
||||||
* Read contents of the configured property file.
|
* Read contents of the configured property file.
|
||||||
*
|
*
|
||||||
* @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
|
* @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map,
|
||||||
|
* java.util.Map)
|
||||||
* @param subject
|
* @param subject
|
||||||
* @param callbackHandler
|
* @param callbackHandler
|
||||||
* @param sharedState
|
* @param sharedState
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
public void initialize(Subject subject, CallbackHandler callbackHandler,
|
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
|
||||||
Map<String,?> sharedState, Map<String,?> options)
|
|
||||||
{
|
{
|
||||||
super.initialize(subject, callbackHandler, sharedState, options);
|
super.initialize(subject,callbackHandler,sharedState,options);
|
||||||
loadProperties((String)options.get("file"));
|
setupPropertyUserStore(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void loadProperties (String filename)
|
|
||||||
{
|
|
||||||
File propsFile;
|
|
||||||
|
|
||||||
if (filename == null)
|
|
||||||
{
|
|
||||||
propsFile = new File(System.getProperty("user.dir"), DEFAULT_FILENAME);
|
|
||||||
//look for a file called realm.properties in the current directory
|
|
||||||
//if that fails, look for a file called realm.properties in $jetty.home/etc
|
|
||||||
if (!propsFile.exists())
|
|
||||||
propsFile = new File(System.getProperty("jetty.home"), DEFAULT_FILENAME);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
propsFile = new File(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
//give up, can't find a property file to load
|
|
||||||
if (!propsFile.exists())
|
|
||||||
{
|
|
||||||
LOG.warn("No property file found");
|
|
||||||
throw new IllegalStateException ("No property file specified in login module configuration file");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.propertyFileName = propsFile.getCanonicalPath();
|
|
||||||
if (fileMap.get(propertyFileName) != null)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled()) {LOG.debug("Properties file "+propertyFileName+" already in cache, skipping load");}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, UserInfo> userInfoMap = new HashMap<String, UserInfo>();
|
|
||||||
Properties props = new Properties();
|
|
||||||
props.load(new FileInputStream(propsFile));
|
|
||||||
Iterator<Map.Entry<Object,Object>> iter = props.entrySet().iterator();
|
|
||||||
while(iter.hasNext())
|
|
||||||
{
|
|
||||||
|
|
||||||
Map.Entry<Object,Object> entry = iter.next();
|
|
||||||
String username=entry.getKey().toString().trim();
|
|
||||||
String credentials=entry.getValue().toString().trim();
|
|
||||||
String roles=null;
|
|
||||||
int c=credentials.indexOf(',');
|
|
||||||
if (c>0)
|
|
||||||
{
|
|
||||||
roles=credentials.substring(c+1).trim();
|
|
||||||
credentials=credentials.substring(0,c).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (username!=null && username.length()>0 &&
|
private void setupPropertyUserStore(Map<String, ?> options)
|
||||||
credentials!=null && credentials.length()>0)
|
{
|
||||||
{
|
if (_propertyUserStores.get(_filename) == null)
|
||||||
ArrayList<String> roleList = new ArrayList<String>();
|
|
||||||
if(roles!=null && roles.length()>0)
|
|
||||||
{
|
|
||||||
StringTokenizer tok = new StringTokenizer(roles,", ");
|
|
||||||
|
|
||||||
while (tok.hasMoreTokens())
|
|
||||||
roleList.add(tok.nextToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
userInfoMap.put(username, (new UserInfo(username, Credential.getCredential(credentials.toString()), roleList)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileMap.put(propertyFileName, userInfoMap);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
LOG.warn("Error loading properties from file", e);
|
parseConfig(options);
|
||||||
throw new RuntimeException(e);
|
|
||||||
|
PropertyUserStore _propertyUserStore = new PropertyUserStore();
|
||||||
|
_propertyUserStore.setConfig(_filename);
|
||||||
|
_propertyUserStore.setRefreshInterval(_refreshInterval);
|
||||||
|
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_propertyUserStore.start();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Exception while starting propertyUserStore: ",e);
|
||||||
|
}
|
||||||
|
|
||||||
|
_propertyUserStores.put(_filename,_propertyUserStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void parseConfig(Map<String, ?> options)
|
||||||
* Don't implement this as we want to pre-fetch all of the
|
{
|
||||||
* users.
|
_filename = (String)options.get("file") != null?(String)options.get("file"):DEFAULT_FILENAME;
|
||||||
* @param username
|
String refreshIntervalString = (String)options.get("refreshInterval");
|
||||||
|
_refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't implement this as we want to pre-fetch all of the users.
|
||||||
|
*
|
||||||
|
* @param userName
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public UserInfo getUserInfo (String username) throws Exception
|
public UserInfo getUserInfo(String userName) throws Exception
|
||||||
{
|
{
|
||||||
Map<?, ?> userInfoMap = (Map<?, ?>)fileMap.get(propertyFileName);
|
PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename);
|
||||||
if (userInfoMap == null)
|
if (propertyUserStore == null)
|
||||||
|
throw new IllegalStateException("PropertyUserStore should never be null here!");
|
||||||
|
|
||||||
|
UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
|
||||||
|
if(userIdentity==null)
|
||||||
return null;
|
return null;
|
||||||
return (UserInfo)userInfoMap.get(username);
|
|
||||||
|
Set<Principal> principals = userIdentity.getSubject().getPrincipals();
|
||||||
|
|
||||||
|
List<String> roles = new ArrayList<String>();
|
||||||
|
|
||||||
|
for ( Principal principal : principals )
|
||||||
|
{
|
||||||
|
roles.add( principal.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next();
|
||||||
|
LOG.debug("Found: " + userName + " in PropertyUserStore");
|
||||||
|
return new UserInfo(userName, credential, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -74,10 +74,11 @@
|
||||||
<artifactId>jetty-server</artifactId>
|
<artifactId>jetty-server</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${servlet.spec.groupId}</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>${servlet.spec.artifactId}</artifactId>
|
<artifactId>jetty-client</artifactId>
|
||||||
</dependency>
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>test-jetty-servlet</artifactId>
|
<artifactId>test-jetty-servlet</artifactId>
|
||||||
|
|
|
@ -0,0 +1,487 @@
|
||||||
|
package org.eclipse.jetty.rewrite.handler;
|
||||||
|
|
||||||
|
//========================================================================
|
||||||
|
//Copyright (c) 2006-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.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
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.http.HttpURI;
|
||||||
|
import org.eclipse.jetty.http.PathMap;
|
||||||
|
import org.eclipse.jetty.io.Buffer;
|
||||||
|
import org.eclipse.jetty.io.EofException;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This rule allows the user to configure a particular rewrite rule that will proxy out
|
||||||
|
* to a configured location. This rule uses the jetty http client.
|
||||||
|
*
|
||||||
|
* Rule rule = new ProxyRule();
|
||||||
|
* rule.setPattern("/foo/*");
|
||||||
|
* rule.setProxyTo("http://url.com");
|
||||||
|
*
|
||||||
|
* see api for other configuration options which influence the configuration of the jetty
|
||||||
|
* client instance
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProxyRule extends PatternRule
|
||||||
|
{
|
||||||
|
private static final Logger _log = Log.getLogger(ProxyRule.class);
|
||||||
|
|
||||||
|
private HttpClient _client;
|
||||||
|
private String _hostHeader;
|
||||||
|
private String _proxyTo;
|
||||||
|
|
||||||
|
private int _connectorType = 2;
|
||||||
|
private String _maxThreads;
|
||||||
|
private String _maxConnections;
|
||||||
|
private String _timeout;
|
||||||
|
private String _idleTimeout;
|
||||||
|
private String _requestHeaderSize;
|
||||||
|
private String _requestBufferSize;
|
||||||
|
private String _responseHeaderSize;
|
||||||
|
private String _responseBufferSize;
|
||||||
|
|
||||||
|
private HashSet<String> _DontProxyHeaders = new HashSet<String>();
|
||||||
|
{
|
||||||
|
_DontProxyHeaders.add("proxy-connection");
|
||||||
|
_DontProxyHeaders.add("connection");
|
||||||
|
_DontProxyHeaders.add("keep-alive");
|
||||||
|
_DontProxyHeaders.add("transfer-encoding");
|
||||||
|
_DontProxyHeaders.add("te");
|
||||||
|
_DontProxyHeaders.add("trailer");
|
||||||
|
_DontProxyHeaders.add("proxy-authorization");
|
||||||
|
_DontProxyHeaders.add("proxy-authenticate");
|
||||||
|
_DontProxyHeaders.add("upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public ProxyRule()
|
||||||
|
{
|
||||||
|
_handling = true;
|
||||||
|
_terminating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private void initializeClient() throws Exception
|
||||||
|
{
|
||||||
|
_client = new HttpClient();
|
||||||
|
_client.setConnectorType(_connectorType);
|
||||||
|
|
||||||
|
if ( _maxThreads != null )
|
||||||
|
{
|
||||||
|
_client.setThreadPool(new QueuedThreadPool(Integer.parseInt(_maxThreads)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_client.setThreadPool(new QueuedThreadPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _maxConnections != null )
|
||||||
|
{
|
||||||
|
_client.setMaxConnectionsPerAddress(Integer.parseInt(_maxConnections));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _timeout != null )
|
||||||
|
{
|
||||||
|
_client.setTimeout(Long.parseLong(_timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _idleTimeout != null )
|
||||||
|
{
|
||||||
|
_client.setIdleTimeout(Long.parseLong(_idleTimeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _requestBufferSize != null )
|
||||||
|
{
|
||||||
|
_client.setRequestBufferSize(Integer.parseInt(_requestBufferSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _requestHeaderSize != null )
|
||||||
|
{
|
||||||
|
_client.setRequestHeaderSize(Integer.parseInt(_requestHeaderSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _responseBufferSize != null )
|
||||||
|
{
|
||||||
|
_client.setResponseBufferSize(Integer.parseInt(_responseBufferSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _responseHeaderSize != null )
|
||||||
|
{
|
||||||
|
_client.setResponseHeaderSize(Integer.parseInt(_responseHeaderSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private HttpURI proxyHttpURI(String uri) throws MalformedURLException
|
||||||
|
{
|
||||||
|
return new HttpURI(_proxyTo + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
protected String apply(String target, HttpServletRequest request, final HttpServletResponse response) throws IOException
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (_client == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initializeClient();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new IOException("Unable to proxy: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int debug = _log.isDebugEnabled()?request.hashCode():0;
|
||||||
|
|
||||||
|
final InputStream in = request.getInputStream();
|
||||||
|
final OutputStream out = response.getOutputStream();
|
||||||
|
|
||||||
|
HttpURI url = createUrl(request,debug);
|
||||||
|
|
||||||
|
if (url == null)
|
||||||
|
{
|
||||||
|
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpExchange exchange = new HttpExchange()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void onRequestCommitted() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRequestComplete() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResponseComplete() throws IOException
|
||||||
|
{
|
||||||
|
if (debug != 0)
|
||||||
|
_log.debug(debug + " complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResponseContent(Buffer content) throws IOException
|
||||||
|
{
|
||||||
|
if (debug != 0)
|
||||||
|
_log.debug(debug + " content" + content.length());
|
||||||
|
content.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResponseHeaderComplete() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||||
|
{
|
||||||
|
if (debug != 0)
|
||||||
|
_log.debug(debug + " " + version + " " + status + " " + reason);
|
||||||
|
|
||||||
|
if (reason != null && reason.length() > 0)
|
||||||
|
response.setStatus(status,reason.toString());
|
||||||
|
else
|
||||||
|
response.setStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||||
|
{
|
||||||
|
String s = name.toString().toLowerCase();
|
||||||
|
if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value)))
|
||||||
|
{
|
||||||
|
if (debug != 0)
|
||||||
|
_log.debug(debug + " " + name + ": " + value);
|
||||||
|
|
||||||
|
response.addHeader(name.toString(),value.toString());
|
||||||
|
}
|
||||||
|
else if (debug != 0)
|
||||||
|
_log.debug(debug + " " + name + "! " + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConnectionFailed(Throwable ex)
|
||||||
|
{
|
||||||
|
_log.warn(ex.toString());
|
||||||
|
_log.debug(ex);
|
||||||
|
if (!response.isCommitted())
|
||||||
|
{
|
||||||
|
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onException(Throwable ex)
|
||||||
|
{
|
||||||
|
if (ex instanceof EofException)
|
||||||
|
{
|
||||||
|
_log.ignore(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_log.warn(ex.toString());
|
||||||
|
_log.debug(ex);
|
||||||
|
if (!response.isCommitted())
|
||||||
|
{
|
||||||
|
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onExpire()
|
||||||
|
{
|
||||||
|
if (!response.isCommitted())
|
||||||
|
{
|
||||||
|
response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
exchange.setMethod(request.getMethod());
|
||||||
|
exchange.setURL(url.toString());
|
||||||
|
exchange.setVersion(request.getProtocol());
|
||||||
|
|
||||||
|
if (debug != 0)
|
||||||
|
{
|
||||||
|
_log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasContent = createHeaders(request,debug,exchange);
|
||||||
|
|
||||||
|
if (hasContent)
|
||||||
|
{
|
||||||
|
exchange.setRequestContentSource(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we need to set the timeout on the exchange to take into account the timeout of the HttpClient and the HttpExchange
|
||||||
|
*/
|
||||||
|
long ctimeout = (_client.getTimeout() > exchange.getTimeout())?_client.getTimeout():exchange.getTimeout();
|
||||||
|
exchange.setTimeout(ctimeout);
|
||||||
|
|
||||||
|
_client.send(exchange);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
exchange.waitForDone();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
_log.info("Exception while waiting for response on proxied request", e);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException
|
||||||
|
{
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
|
||||||
|
if (request.getQueryString() != null)
|
||||||
|
{
|
||||||
|
uri += "?" + request.getQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = PathMap.pathInfo(_pattern,uri);
|
||||||
|
|
||||||
|
if(uri==null)
|
||||||
|
{
|
||||||
|
uri = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpURI url = proxyHttpURI(uri);
|
||||||
|
|
||||||
|
if (debug != 0)
|
||||||
|
{
|
||||||
|
_log.debug(debug + " proxy " + uri + "-->" + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange)
|
||||||
|
{
|
||||||
|
// check connection header
|
||||||
|
String connectionHdr = request.getHeader("Connection");
|
||||||
|
if (connectionHdr != null)
|
||||||
|
{
|
||||||
|
connectionHdr = connectionHdr.toLowerCase();
|
||||||
|
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
|
||||||
|
{
|
||||||
|
connectionHdr = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// force host
|
||||||
|
if (_hostHeader != null)
|
||||||
|
{
|
||||||
|
exchange.setRequestHeader("Host",_hostHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy headers
|
||||||
|
boolean xForwardedFor = false;
|
||||||
|
boolean hasContent = false;
|
||||||
|
long contentLength = -1;
|
||||||
|
Enumeration<?> enm = request.getHeaderNames();
|
||||||
|
while (enm.hasMoreElements())
|
||||||
|
{
|
||||||
|
// TODO could be better than this!
|
||||||
|
String hdr = (String)enm.nextElement();
|
||||||
|
String lhdr = hdr.toLowerCase();
|
||||||
|
|
||||||
|
if (_DontProxyHeaders.contains(lhdr))
|
||||||
|
continue;
|
||||||
|
if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0)
|
||||||
|
continue;
|
||||||
|
if (_hostHeader != null && "host".equals(lhdr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ("content-type".equals(lhdr))
|
||||||
|
hasContent = true;
|
||||||
|
else if ("content-length".equals(lhdr))
|
||||||
|
{
|
||||||
|
contentLength = request.getContentLength();
|
||||||
|
exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(contentLength));
|
||||||
|
if (contentLength > 0)
|
||||||
|
hasContent = true;
|
||||||
|
}
|
||||||
|
else if ("x-forwarded-for".equals(lhdr))
|
||||||
|
xForwardedFor = true;
|
||||||
|
|
||||||
|
Enumeration<?> vals = request.getHeaders(hdr);
|
||||||
|
while (vals.hasMoreElements())
|
||||||
|
{
|
||||||
|
String val = (String)vals.nextElement();
|
||||||
|
if (val != null)
|
||||||
|
{
|
||||||
|
if (debug != 0)
|
||||||
|
_log.debug(debug + " " + hdr + ": " + val);
|
||||||
|
|
||||||
|
exchange.setRequestHeader(hdr,val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy headers
|
||||||
|
exchange.setRequestHeader("Via","1.1 (jetty)");
|
||||||
|
if (!xForwardedFor)
|
||||||
|
{
|
||||||
|
exchange.addRequestHeader("X-Forwarded-For",request.getRemoteAddr());
|
||||||
|
exchange.addRequestHeader("X-Forwarded-Proto",request.getScheme());
|
||||||
|
exchange.addRequestHeader("X-Forwarded-Host",request.getServerName());
|
||||||
|
exchange.addRequestHeader("X-Forwarded-Server",request.getLocalName());
|
||||||
|
}
|
||||||
|
return hasContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setProxyTo(String proxyTo)
|
||||||
|
{
|
||||||
|
this._proxyTo = proxyTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setMaxThreads(String maxThreads)
|
||||||
|
{
|
||||||
|
this._maxThreads = maxThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setMaxConnections(String maxConnections)
|
||||||
|
{
|
||||||
|
_maxConnections = maxConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setTimeout(String timeout)
|
||||||
|
{
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setIdleTimeout(String idleTimeout)
|
||||||
|
{
|
||||||
|
_idleTimeout = idleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setRequestHeaderSize(String requestHeaderSize)
|
||||||
|
{
|
||||||
|
_requestHeaderSize = requestHeaderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setRequestBufferSize(String requestBufferSize)
|
||||||
|
{
|
||||||
|
_requestBufferSize = requestBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setResponseHeaderSize(String responseHeaderSize)
|
||||||
|
{
|
||||||
|
_responseHeaderSize = responseHeaderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setResponseBufferSize(String responseBufferSize)
|
||||||
|
{
|
||||||
|
_responseBufferSize = responseBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void addDontProxyHeaders(String dontProxyHeader)
|
||||||
|
{
|
||||||
|
_DontProxyHeaders.add(dontProxyHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* CONNECTOR_SOCKET = 0;
|
||||||
|
* CONNECTOR_SELECT_CHANNEL = 2; (default)
|
||||||
|
*
|
||||||
|
* @param connectorType
|
||||||
|
*/
|
||||||
|
public void setConnectorType( int connectorType )
|
||||||
|
{
|
||||||
|
_connectorType = connectorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,11 +5,11 @@
|
||||||
// All rights reserved. This program and the accompanying materials
|
// All rights reserved. This program and the accompanying materials
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
// 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
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
// The Apache License v2.0 is available at
|
// The Apache License v2.0 is available at
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
// 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.rewrite.handler;
|
package org.eclipse.jetty.rewrite.handler;
|
||||||
|
|
||||||
|
@ -19,25 +19,24 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.PathMap;
|
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
*<p> Rewrite handler is responsible for managing the rules. Its capabilities
|
*<p> Rewrite handler is responsible for managing the rules. Its capabilities
|
||||||
* is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule.
|
* is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule.
|
||||||
* There is also handling for cookies, headers, redirection, setting status or error codes
|
* There is also handling for cookies, headers, redirection, setting status or error codes
|
||||||
* whenever the rule finds a match.
|
* whenever the rule finds a match.
|
||||||
*
|
*
|
||||||
* <p> The rules can be matched by the either: pattern matching of PathMap
|
* <p> The rules can be matched by the either: pattern matching of PathMap
|
||||||
* (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set
|
* (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set
|
||||||
* (eg {@link MsieSslRule} - the requests must be in SSL mode).
|
* (eg {@link MsieSslRule} - the requests must be in SSL mode).
|
||||||
*
|
*
|
||||||
* <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only
|
* <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only
|
||||||
* be applied if the request matches the conditions for their container
|
* be applied if the request matches the conditions for their container
|
||||||
* (e.g., by virtual host name)
|
* (e.g., by virtual host name)
|
||||||
*
|
*
|
||||||
* <p>The list of predefined rules is:
|
* <p>The list of predefined rules is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> {@link CookiePatternRule} - adds a new cookie in response. </li>
|
* <li> {@link CookiePatternRule} - adds a new cookie in response. </li>
|
||||||
|
@ -46,28 +45,36 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* <li> {@link ResponsePatternRule} - sets the status/error codes. </li>
|
* <li> {@link ResponsePatternRule} - sets the status/error codes. </li>
|
||||||
* <li> {@link RewritePatternRule} - rewrites the requested URI. </li>
|
* <li> {@link RewritePatternRule} - rewrites the requested URI. </li>
|
||||||
* <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li>
|
* <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li>
|
||||||
|
* <li> {@link ProxyRule} - proxies the requested URI to the host defined in proxyTo. </li>
|
||||||
* <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li>
|
* <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li>
|
||||||
* <li> {@link LegacyRule} - the old version of rewrite. </li>
|
* <li> {@link LegacyRule} - the old version of rewrite. </li>
|
||||||
* <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li>
|
* <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li>
|
||||||
* <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li>
|
* <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Here is a typical jetty.xml configuration would be: <pre>
|
* Here is a typical jetty.xml configuration would be: <pre>
|
||||||
*
|
*
|
||||||
* <Set name="handler">
|
* <Set name="handler">
|
||||||
* <New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
* <New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
||||||
* <Set name="rules">
|
* <Set name="rules">
|
||||||
* <Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
* <Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
* <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||||
* <Set name="pattern">/*</Set>
|
* <Set name="pattern">/*</Set>
|
||||||
* <Set name="replacement">/test</Set>
|
* <Set name="replacement">/test</Set>
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
|
* <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.ProxyRule">
|
||||||
|
* <Set name="pattern">/*</Set>
|
||||||
|
* <Set name="proxyTo">http://webtide.com:8080</Set>
|
||||||
|
* </New>
|
||||||
|
* </Item>
|
||||||
|
*
|
||||||
|
* <Item>
|
||||||
* <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
* <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
||||||
* <Set name="pattern">/session/</Set>
|
* <Set name="pattern">/session/</Set>
|
||||||
* <Set name="code">400</Set>
|
* <Set name="code">400</Set>
|
||||||
|
@ -75,7 +82,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||||
* <Set name="pattern">*.jsp</Set>
|
* <Set name="pattern">*.jsp</Set>
|
||||||
* <Set name="name">server</Set>
|
* <Set name="name">server</Set>
|
||||||
|
@ -83,7 +90,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||||
* <Set name="pattern">*.jsp</Set>
|
* <Set name="pattern">*.jsp</Set>
|
||||||
* <Set name="name">title</Set>
|
* <Set name="name">title</Set>
|
||||||
|
@ -91,28 +98,28 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
* <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||||
* <Set name="pattern">/test/dispatch</Set>
|
* <Set name="pattern">/test/dispatch</Set>
|
||||||
* <Set name="location">http://jetty.eclipse.org</Set>
|
* <Set name="location">http://jetty.eclipse.org</Set>
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
|
* <New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
|
||||||
* <Set name="regex">/test-jaas/$</Set>
|
* <Set name="regex">/test-jaas/$</Set>
|
||||||
* <Set name="replacement">/demo</Set>
|
* <Set name="replacement">/demo</Set>
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule">
|
* <New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule">
|
||||||
* <Set name="header">X-Forwarded-Scheme</Set>
|
* <Set name="header">X-Forwarded-Scheme</Set>
|
||||||
* <Set name="headerValue">https</Set>
|
* <Set name="headerValue">https</Set>
|
||||||
* <Set name="scheme">https</Set>
|
* <Set name="scheme">https</Set>
|
||||||
* </New>
|
* </New>
|
||||||
* </Item>
|
* </Item>
|
||||||
*
|
*
|
||||||
* <Item>
|
* <Item>
|
||||||
* <New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
|
* <New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
|
||||||
*
|
*
|
||||||
|
@ -134,10 +141,10 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* </New>
|
* </New>
|
||||||
* </Arg>
|
* </Arg>
|
||||||
* </Call>
|
* </Call>
|
||||||
*
|
*
|
||||||
* </New>
|
* </New>
|
||||||
* </ Item>
|
* </ Item>
|
||||||
*
|
*
|
||||||
* </Array>
|
* </Array>
|
||||||
* </Set>
|
* </Set>
|
||||||
*
|
*
|
||||||
|
@ -162,13 +169,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
* </New>
|
* </New>
|
||||||
* </Set>
|
* </Set>
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RewriteHandler extends HandlerWrapper
|
public class RewriteHandler extends HandlerWrapper
|
||||||
{
|
{
|
||||||
|
|
||||||
private RuleContainer _rules;
|
private RuleContainer _rules;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public RewriteHandler()
|
public RewriteHandler()
|
||||||
{
|
{
|
||||||
|
@ -179,7 +186,7 @@ public class RewriteHandler extends HandlerWrapper
|
||||||
/**
|
/**
|
||||||
* To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
|
* To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
|
||||||
* originalPathAttribute
|
* originalPathAttribute
|
||||||
*
|
*
|
||||||
* @param legacyRule old style rewrite rule
|
* @param legacyRule old style rewrite rule
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -201,7 +208,7 @@ public class RewriteHandler extends HandlerWrapper
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Assigns the rules to process.
|
* Assigns the rules to process.
|
||||||
* @param rules an array of {@link Rule}.
|
* @param rules an array of {@link Rule}.
|
||||||
*/
|
*/
|
||||||
public void setRules(Rule[] rules)
|
public void setRules(Rule[] rules)
|
||||||
{
|
{
|
||||||
|
@ -297,13 +304,13 @@ public class RewriteHandler extends HandlerWrapper
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
if (isStarted())
|
if (isStarted())
|
||||||
{
|
{
|
||||||
String returned = _rules.matchAndApply(target, request, response);
|
String returned = _rules.matchAndApply(target, request, response);
|
||||||
target = (returned == null) ? target : returned;
|
target = (returned == null) ? target : returned;
|
||||||
|
|
||||||
if (!baseRequest.isHandled())
|
if (!baseRequest.isHandled())
|
||||||
super.handle(target, baseRequest, request, response);
|
super.handle(target, baseRequest, request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
package org.eclipse.jetty.rewrite.handler;
|
||||||
|
|
||||||
|
//========================================================================
|
||||||
|
//Copyright (c) 2006-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.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.ContentExchange;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.client.HttpExchange;
|
||||||
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
|
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.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ProxyRuleTest
|
||||||
|
{
|
||||||
|
private static ProxyRule _rule;
|
||||||
|
private static RewriteHandler _handler;
|
||||||
|
private static Server _proxyServer = new Server();
|
||||||
|
private static Connector _proxyServerConnector = new SelectChannelConnector();
|
||||||
|
private static Server _targetServer = new Server();
|
||||||
|
private static Connector _targetServerConnector = new SelectChannelConnector();
|
||||||
|
private static HttpClient _httpClient = new HttpClient();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setupOnce() throws Exception
|
||||||
|
{
|
||||||
|
_targetServer.addConnector(_targetServerConnector);
|
||||||
|
_targetServer.setHandler(new AbstractHandler()
|
||||||
|
{
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
String responseString = "uri: " + request.getRequestURI() + " some content";
|
||||||
|
response.getOutputStream().write(responseString.getBytes());
|
||||||
|
response.setStatus(201);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_targetServer.start();
|
||||||
|
|
||||||
|
_rule = new ProxyRule();
|
||||||
|
_rule.setPattern("/foo/*");
|
||||||
|
_rule.setProxyTo("http://localhost:" + _targetServerConnector.getLocalPort());
|
||||||
|
_handler = new RewriteHandler();
|
||||||
|
_handler.setRewriteRequestURI(true);
|
||||||
|
_handler.setRules(new Rule[] { _rule });
|
||||||
|
|
||||||
|
_proxyServer.addConnector(_proxyServerConnector);
|
||||||
|
_proxyServer.setHandler(_handler);
|
||||||
|
_proxyServer.start();
|
||||||
|
|
||||||
|
_httpClient.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void destroy() throws Exception
|
||||||
|
{
|
||||||
|
_httpClient.stop();
|
||||||
|
_proxyServer.stop();
|
||||||
|
_targetServer.stop();
|
||||||
|
_rule = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProxy() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
ContentExchange exchange = new ContentExchange(true);
|
||||||
|
exchange.setMethod(HttpMethods.GET);
|
||||||
|
String body = "BODY";
|
||||||
|
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo?body=" + URLEncoder.encode(body,"UTF-8");
|
||||||
|
exchange.setURL(url);
|
||||||
|
|
||||||
|
_httpClient.send(exchange);
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||||
|
assertEquals("uri: / some content",exchange.getResponseContent());
|
||||||
|
assertEquals(201,exchange.getResponseStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProxyWithDeeperPath() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
ContentExchange exchange = new ContentExchange(true);
|
||||||
|
exchange.setMethod(HttpMethods.GET);
|
||||||
|
String body = "BODY";
|
||||||
|
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo/bar/foobar?body=" + URLEncoder.encode(body,"UTF-8");
|
||||||
|
exchange.setURL(url);
|
||||||
|
|
||||||
|
_httpClient.send(exchange);
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||||
|
assertEquals("uri: /bar/foobar some content",exchange.getResponseContent());
|
||||||
|
assertEquals(201,exchange.getResponseStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProxyNoMatch() throws Exception
|
||||||
|
{
|
||||||
|
ContentExchange exchange = new ContentExchange(true);
|
||||||
|
exchange.setMethod(HttpMethods.GET);
|
||||||
|
String body = "BODY";
|
||||||
|
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foobar?body=" + URLEncoder.encode(body,"UTF-8");
|
||||||
|
exchange.setURL(url);
|
||||||
|
|
||||||
|
_httpClient.send(exchange);
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||||
|
assertEquals(404,exchange.getResponseStatus());
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,9 @@ import java.security.Principal;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.security.Credential;
|
||||||
|
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
||||||
|
import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,21 +13,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.security;
|
package org.eclipse.jetty.security;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.http.security.Credential;
|
import org.eclipse.jetty.http.security.Credential;
|
||||||
|
import org.eclipse.jetty.security.PropertyUserStore.UserListener;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.util.Scanner;
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.Scanner.BulkListener;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
@ -36,27 +27,24 @@ import org.eclipse.jetty.util.resource.Resource;
|
||||||
/**
|
/**
|
||||||
* Properties User Realm.
|
* Properties User Realm.
|
||||||
*
|
*
|
||||||
* An implementation of UserRealm that stores users and roles in-memory in
|
* An implementation of UserRealm that stores users and roles in-memory in HashMaps.
|
||||||
* HashMaps.
|
|
||||||
* <P>
|
* <P>
|
||||||
* Typically these maps are populated by calling the load() method or passing a
|
* Typically these maps are populated by calling the load() method or passing a properties resource to the constructor. The format of the properties file is:
|
||||||
* properties resource to the constructor. The format of the properties file is:
|
|
||||||
*
|
*
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* username: password [,rolename ...]
|
* username: password [,rolename ...]
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*
|
*
|
||||||
* Passwords may be clear text, obfuscated or checksummed. The class
|
* Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
|
||||||
* com.eclipse.Util.Password should be used to generate obfuscated passwords or
|
* checksums.
|
||||||
* password checksums.
|
|
||||||
*
|
*
|
||||||
* If DIGEST Authentication is used, the password must be in a recoverable
|
* If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
|
||||||
* format, either plain text or OBF:.
|
|
||||||
*/
|
*/
|
||||||
public class HashLoginService extends MappedLoginService
|
public class HashLoginService extends MappedLoginService implements UserListener
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
||||||
|
|
||||||
|
private PropertyUserStore _propertyUserStore;
|
||||||
private String _config;
|
private String _config;
|
||||||
private Resource _configResource;
|
private Resource _configResource;
|
||||||
private Scanner _scanner;
|
private Scanner _scanner;
|
||||||
|
@ -72,14 +60,14 @@ public class HashLoginService extends MappedLoginService
|
||||||
{
|
{
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public HashLoginService(String name, String config)
|
public HashLoginService(String name, String config)
|
||||||
{
|
{
|
||||||
setName(name);
|
setName(name);
|
||||||
setConfig(config);
|
setConfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public String getConfig()
|
public String getConfig()
|
||||||
{
|
{
|
||||||
|
@ -89,7 +77,7 @@ public class HashLoginService extends MappedLoginService
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void getConfig(String config)
|
public void getConfig(String config)
|
||||||
{
|
{
|
||||||
_config=config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -100,11 +88,10 @@ public class HashLoginService extends MappedLoginService
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Load realm users from properties file. The property file maps usernames
|
* Load realm users from properties file. The property file maps usernames to password specs followed by an optional comma separated list of role names.
|
||||||
* to password specs followed by an optional comma separated list of role
|
|
||||||
* names.
|
|
||||||
*
|
*
|
||||||
* @param config Filename or url of user properties file.
|
* @param config
|
||||||
|
* Filename or url of user properties file.
|
||||||
*/
|
*/
|
||||||
public void setConfig(String config)
|
public void setConfig(String config)
|
||||||
{
|
{
|
||||||
|
@ -129,52 +116,14 @@ public class HashLoginService extends MappedLoginService
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public void loadUsers() throws IOException
|
public void loadUsers() throws IOException
|
||||||
{
|
{
|
||||||
if (_config==null)
|
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
|
||||||
return;
|
|
||||||
_configResource = Resource.newResource(_config);
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Load " + this + " from " + _config);
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.load(_configResource.getInputStream());
|
|
||||||
Set<String> known = new HashSet<String>();
|
|
||||||
|
|
||||||
for (Map.Entry<Object, Object> entry : properties.entrySet())
|
|
||||||
{
|
|
||||||
String username = ((String) entry.getKey()).trim();
|
|
||||||
String credentials = ((String) entry.getValue()).trim();
|
|
||||||
String roles = null;
|
|
||||||
int c = credentials.indexOf(',');
|
|
||||||
if (c > 0)
|
|
||||||
{
|
|
||||||
roles = credentials.substring(c + 1).trim();
|
|
||||||
credentials = credentials.substring(0, c).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
|
|
||||||
{
|
|
||||||
String[] roleArray = IdentityService.NO_ROLES;
|
|
||||||
if (roles != null && roles.length() > 0)
|
|
||||||
roleArray = roles.split(",");
|
|
||||||
known.add(username);
|
|
||||||
putUser(username,Credential.getCredential(credentials),roleArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<String> users = _users.keySet().iterator();
|
|
||||||
while(users.hasNext())
|
|
||||||
{
|
|
||||||
String user=users.next();
|
|
||||||
if (!known.contains(user))
|
|
||||||
users.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||||
|
@ -183,54 +132,17 @@ public class HashLoginService extends MappedLoginService
|
||||||
{
|
{
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
|
||||||
if (getRefreshInterval() > 0)
|
if (_propertyUserStore == null)
|
||||||
{
|
{
|
||||||
_scanner = new Scanner();
|
if(LOG.isDebugEnabled())
|
||||||
_scanner.setScanInterval(getRefreshInterval());
|
|
||||||
List<File> dirList = new ArrayList<File>(1);
|
|
||||||
dirList.add(_configResource.getFile());
|
|
||||||
_scanner.setScanDirs(dirList);
|
|
||||||
_scanner.setFilenameFilter(new FilenameFilter()
|
|
||||||
{
|
{
|
||||||
public boolean accept(File dir, String name)
|
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
|
||||||
{
|
}
|
||||||
File f = new File(dir, name);
|
_propertyUserStore = new PropertyUserStore();
|
||||||
try
|
_propertyUserStore.setRefreshInterval(_refreshInterval);
|
||||||
{
|
_propertyUserStore.setConfig(_config);
|
||||||
if (f.compareTo(_configResource.getFile()) == 0) return true;
|
_propertyUserStore.registerUserListener(this);
|
||||||
}
|
_propertyUserStore.start();
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
_scanner.addListener(new BulkListener()
|
|
||||||
{
|
|
||||||
public void filesChanged(List<String> filenames) throws Exception
|
|
||||||
{
|
|
||||||
if (filenames == null) return;
|
|
||||||
if (filenames.isEmpty()) return;
|
|
||||||
if (filenames.size() == 1)
|
|
||||||
{
|
|
||||||
Resource r = Resource.newResource(filenames.get(0));
|
|
||||||
if (r.getFile().equals(_configResource.getFile()))
|
|
||||||
loadUsers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "HashLoginService$Scanner";
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
_scanner.setReportExistingFilesOnStartup(false);
|
|
||||||
_scanner.setRecursive(false);
|
|
||||||
_scanner.start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,9 +153,24 @@ public class HashLoginService extends MappedLoginService
|
||||||
protected void doStop() throws Exception
|
protected void doStop() throws Exception
|
||||||
{
|
{
|
||||||
super.doStop();
|
super.doStop();
|
||||||
if (_scanner != null) _scanner.stop();
|
if (_scanner != null)
|
||||||
|
_scanner.stop();
|
||||||
_scanner = null;
|
_scanner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void update(String userName, Credential credential, String[] roleArray)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("update: " + userName + " Roles: " + roleArray.length);
|
||||||
|
putUser(userName,credential,roleArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void remove(String userName)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("remove: " + userName);
|
||||||
|
removeUser(userName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
package org.eclipse.jetty.security;
|
package org.eclipse.jetty.security;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.security.Credential;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.UserIdentity;
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ package org.eclipse.jetty.security;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -11,7 +13,12 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.security.Credential;
|
import org.eclipse.jetty.http.security.Credential;
|
||||||
|
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
||||||
|
import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
|
||||||
|
import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.util.Scanner;
|
import org.eclipse.jetty.util.Scanner;
|
||||||
import org.eclipse.jetty.util.Scanner.BulkListener;
|
import org.eclipse.jetty.util.Scanner.BulkListener;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
@ -42,8 +49,10 @@ public class PropertyUserStore extends AbstractLifeCycle
|
||||||
private Scanner _scanner;
|
private Scanner _scanner;
|
||||||
private int _refreshInterval = 0;// default is not to reload
|
private int _refreshInterval = 0;// default is not to reload
|
||||||
|
|
||||||
|
private IdentityService _identityService = new DefaultIdentityService();
|
||||||
private boolean _firstLoad = true; // true if first load, false from that point on
|
private boolean _firstLoad = true; // true if first load, false from that point on
|
||||||
private final List<String> _knownUsers = new ArrayList<String>();
|
private final List<String> _knownUsers = new ArrayList<String>();
|
||||||
|
private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
|
||||||
private List<UserListener> _listeners;
|
private List<UserListener> _listeners;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -57,6 +66,12 @@ public class PropertyUserStore extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public UserIdentity getUserIdentity(String userName)
|
||||||
|
{
|
||||||
|
return _knownUserIdentities.get(userName);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
|
@ -119,9 +134,29 @@ public class PropertyUserStore extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
String[] roleArray = IdentityService.NO_ROLES;
|
String[] roleArray = IdentityService.NO_ROLES;
|
||||||
if (roles != null && roles.length() > 0)
|
if (roles != null && roles.length() > 0)
|
||||||
|
{
|
||||||
roleArray = roles.split(",");
|
roleArray = roles.split(",");
|
||||||
|
}
|
||||||
known.add(username);
|
known.add(username);
|
||||||
notifyUpdate(username,Credential.getCredential(credentials),roleArray);
|
Credential credential = Credential.getCredential(credentials);
|
||||||
|
|
||||||
|
Principal userPrincipal = new KnownUser(username,credential);
|
||||||
|
Subject subject = new Subject();
|
||||||
|
subject.getPrincipals().add(userPrincipal);
|
||||||
|
subject.getPrivateCredentials().add(credential);
|
||||||
|
|
||||||
|
if (roles != null)
|
||||||
|
{
|
||||||
|
for (String role : roleArray)
|
||||||
|
{
|
||||||
|
subject.getPrincipals().add(new RolePrincipal(role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subject.setReadOnly();
|
||||||
|
|
||||||
|
_knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roleArray));
|
||||||
|
notifyUpdate(username,credential,roleArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +173,7 @@ public class PropertyUserStore extends AbstractLifeCycle
|
||||||
String user = users.next();
|
String user = users.next();
|
||||||
if (!known.contains(user))
|
if (!known.contains(user))
|
||||||
{
|
{
|
||||||
|
_knownUserIdentities.remove(user);
|
||||||
notifyRemove(user);
|
notifyRemove(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,15 +237,17 @@ public class PropertyUserStore extends AbstractLifeCycle
|
||||||
|
|
||||||
_scanner.addListener(new BulkListener()
|
_scanner.addListener(new BulkListener()
|
||||||
{
|
{
|
||||||
public void filesChanged(List filenames) throws Exception
|
public void filesChanged(List<String> filenames) throws Exception
|
||||||
{
|
{
|
||||||
if (filenames == null)
|
if (filenames == null)
|
||||||
return;
|
return;
|
||||||
if (filenames.isEmpty())
|
if (filenames.isEmpty())
|
||||||
return;
|
return;
|
||||||
if (filenames.size() == 1 && filenames.get(0).equals(getConfigResource().getFile().getAbsolutePath()))
|
if (filenames.size() == 1)
|
||||||
{
|
{
|
||||||
loadUsers();
|
Resource r = Resource.newResource(filenames.get(0));
|
||||||
|
if (r.getFile().equals(_configResource.getFile()))
|
||||||
|
loadUsers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,20 +65,28 @@ public class BasicAuthenticator extends LoginAuthenticator
|
||||||
return _deferred;
|
return _deferred;
|
||||||
|
|
||||||
if (credentials != null)
|
if (credentials != null)
|
||||||
{
|
{
|
||||||
credentials = credentials.substring(credentials.indexOf(' ')+1);
|
int space=credentials.indexOf(' ');
|
||||||
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
|
if (space>0)
|
||||||
int i = credentials.indexOf(':');
|
|
||||||
if (i>0)
|
|
||||||
{
|
{
|
||||||
String username = credentials.substring(0,i);
|
String method=credentials.substring(0,space);
|
||||||
String password = credentials.substring(i+1);
|
if ("basic".equalsIgnoreCase(method))
|
||||||
|
|
||||||
UserIdentity user = _loginService.login(username,password);
|
|
||||||
if (user!=null)
|
|
||||||
{
|
{
|
||||||
renewSessionOnAuthentication(request,response);
|
credentials = credentials.substring(space+1);
|
||||||
return new UserAuthentication(getAuthMethod(),user);
|
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
|
||||||
|
int i = credentials.indexOf(':');
|
||||||
|
if (i>0)
|
||||||
|
{
|
||||||
|
String username = credentials.substring(0,i);
|
||||||
|
String password = credentials.substring(i+1);
|
||||||
|
|
||||||
|
UserIdentity user = _loginService.login(username,password);
|
||||||
|
if (user!=null)
|
||||||
|
{
|
||||||
|
renewSessionOnAuthentication(request,response);
|
||||||
|
return new UserAuthentication(getAuthMethod(),user);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,12 @@ package org.eclipse.jetty.security.authentication;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
|
@ -42,17 +48,29 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
/**
|
/**
|
||||||
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
||||||
*
|
*
|
||||||
* The nonce max age can be set with the {@link SecurityHandler#setInitParameter(String, String)}
|
* The nonce max age in ms can be set with the {@link SecurityHandler#setInitParameter(String, String)}
|
||||||
* using the name "maxNonceAge"
|
* using the name "maxNonceAge"
|
||||||
*/
|
*/
|
||||||
public class DigestAuthenticator extends LoginAuthenticator
|
public class DigestAuthenticator extends LoginAuthenticator
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
||||||
|
SecureRandom _random = new SecureRandom();
|
||||||
|
private long _maxNonceAgeMs = 60*1000;
|
||||||
|
private ConcurrentMap<String, Nonce> _nonceCount = new ConcurrentHashMap<String, Nonce>();
|
||||||
|
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
|
||||||
|
private static class Nonce
|
||||||
|
{
|
||||||
|
final String _nonce;
|
||||||
|
final long _ts;
|
||||||
|
AtomicInteger _nc=new AtomicInteger();
|
||||||
|
public Nonce(String nonce, long ts)
|
||||||
|
{
|
||||||
|
_nonce=nonce;
|
||||||
|
_ts=ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected long _maxNonceAge = 0;
|
/* ------------------------------------------------------------ */
|
||||||
protected long _nonceSecret = this.hashCode() ^ System.currentTimeMillis();
|
|
||||||
protected boolean _useStale = false;
|
|
||||||
|
|
||||||
public DigestAuthenticator()
|
public DigestAuthenticator()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -69,19 +87,22 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
|
|
||||||
String mna=configuration.getInitParameter("maxNonceAge");
|
String mna=configuration.getInitParameter("maxNonceAge");
|
||||||
if (mna!=null)
|
if (mna!=null)
|
||||||
_maxNonceAge=Long.valueOf(mna);
|
_maxNonceAgeMs=Long.valueOf(mna);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
public String getAuthMethod()
|
public String getAuthMethod()
|
||||||
{
|
{
|
||||||
return Constraint.__DIGEST_AUTH;
|
return Constraint.__DIGEST_AUTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
|
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||||
{
|
{
|
||||||
if (!mandatory)
|
if (!mandatory)
|
||||||
|
@ -144,7 +165,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = checkNonce(digest.nonce, (Request)request);
|
int n = checkNonce(digest,(Request)request);
|
||||||
|
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
|
@ -170,8 +191,8 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
+ domain
|
+ domain
|
||||||
+ "\", nonce=\""
|
+ "\", nonce=\""
|
||||||
+ newNonce((Request)request)
|
+ newNonce((Request)request)
|
||||||
+ "\", algorithm=MD5, qop=\"auth\""
|
+ "\", algorithm=MD5, qop=\"auth\","
|
||||||
+ (_useStale ? (" stale=" + stale) : ""));
|
+ " stale=" + stale);
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
|
||||||
return Authentication.SEND_CONTINUE;
|
return Authentication.SEND_CONTINUE;
|
||||||
|
@ -186,87 +207,59 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
public String newNonce(Request request)
|
public String newNonce(Request request)
|
||||||
{
|
{
|
||||||
long ts=request.getTimeStamp();
|
Nonce nonce;
|
||||||
long sk = _nonceSecret;
|
|
||||||
|
do
|
||||||
byte[] nounce = new byte[24];
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
{
|
||||||
nounce[i] = (byte) (ts & 0xff);
|
byte[] nounce = new byte[24];
|
||||||
ts = ts >> 8;
|
_random.nextBytes(nounce);
|
||||||
nounce[8 + i] = (byte) (sk & 0xff);
|
|
||||||
sk = sk >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] hash = null;
|
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
|
||||||
try
|
|
||||||
{
|
|
||||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
||||||
md.reset();
|
|
||||||
md.update(nounce, 0, 16);
|
|
||||||
hash = md.digest();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
|
||||||
{
|
_nonceQueue.add(nonce);
|
||||||
LOG.warn(e);
|
|
||||||
}
|
return nonce._nonce;
|
||||||
|
|
||||||
for (int i = 0; i < hash.length; i++)
|
|
||||||
{
|
|
||||||
nounce[8 + i] = hash[i];
|
|
||||||
if (i == 23) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String(B64Code.encode(nounce));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nonce nonce to check
|
* @param nstring nonce to check
|
||||||
* @param request
|
* @param request
|
||||||
* @return -1 for a bad nonce, 0 for a stale none, 1 for a good nonce
|
* @return -1 for a bad nonce, 0 for a stale none, 1 for a good nonce
|
||||||
*/
|
*/
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private int checkNonce(String nonce, Request request)
|
private int checkNonce(Digest digest, Request request)
|
||||||
{
|
{
|
||||||
|
// firstly let's expire old nonces
|
||||||
|
long expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||||
|
|
||||||
|
Nonce nonce=_nonceQueue.peek();
|
||||||
|
while (nonce!=null && nonce._ts<expired)
|
||||||
|
{
|
||||||
|
_nonceQueue.remove();
|
||||||
|
_nonceCount.remove(nonce._nonce);
|
||||||
|
nonce=_nonceQueue.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] n = B64Code.decode(nonce.toCharArray());
|
nonce = _nonceCount.get(digest.nonce);
|
||||||
if (n.length != 24) return -1;
|
if (nonce==null)
|
||||||
|
return 0;
|
||||||
long ts = 0;
|
|
||||||
long sk = _nonceSecret;
|
long count = Long.parseLong(digest.nc,16);
|
||||||
byte[] n2 = new byte[16];
|
if (count>Integer.MAX_VALUE)
|
||||||
System.arraycopy(n, 0, n2, 0, 8);
|
return 0;
|
||||||
for (int i = 0; i < 8; i++)
|
int old=nonce._nc.get();
|
||||||
{
|
while (!nonce._nc.compareAndSet(old,(int)count))
|
||||||
n2[8 + i] = (byte) (sk & 0xff);
|
old=nonce._nc.get();
|
||||||
sk = sk >> 8;
|
if (count<=old)
|
||||||
ts = (ts << 8) + (0xff & (long) n[7 - i]);
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
long age = request.getTimeStamp() - ts;
|
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("age=" + age);
|
|
||||||
|
|
||||||
byte[] hash = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
||||||
md.reset();
|
|
||||||
md.update(n2, 0, 16);
|
|
||||||
hash = md.digest();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
LOG.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
if (n[i + 8] != hash[i]) return -1;
|
|
||||||
|
|
||||||
if (_maxNonceAge > 0 && (age < 0 || age > _maxNonceAge)) return 0; // stale
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -276,18 +269,21 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
private static class Digest extends Credential
|
private static class Digest extends Credential
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = -2484639019549527724L;
|
private static final long serialVersionUID = -2484639019549527724L;
|
||||||
String method = null;
|
final String method;
|
||||||
String username = null;
|
String username = "";
|
||||||
String realm = null;
|
String realm = "";
|
||||||
String nonce = null;
|
String nonce = "";
|
||||||
String nc = null;
|
String nc = "";
|
||||||
String cnonce = null;
|
String cnonce = "";
|
||||||
String qop = null;
|
String qop = "";
|
||||||
String uri = null;
|
String uri = "";
|
||||||
String response = null;
|
String response = "";
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
Digest(String m)
|
Digest(String m)
|
||||||
|
|
|
@ -201,13 +201,13 @@ public class ConstraintTest
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:wrong") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
@ -218,20 +218,20 @@ public class ConstraintTest
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||||
assertTrue(response.indexOf("!role") > 0);
|
assertTrue(response.indexOf("!role") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
@ -490,18 +490,18 @@ public class ConstraintTest
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:wrong") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
@ -512,20 +512,20 @@ public class ConstraintTest
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||||
assertTrue(response.indexOf("!role") > 0);
|
assertTrue(response.indexOf("!role") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
@ -776,7 +776,7 @@ public class ConstraintTest
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 500 "));
|
assertTrue(response.startsWith("HTTP/1.1 500 "));
|
||||||
|
|
||||||
|
@ -789,7 +789,7 @@ public class ConstraintTest
|
||||||
_server.start();
|
_server.start();
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
}
|
}
|
||||||
|
@ -809,13 +809,13 @@ public class ConstraintTest
|
||||||
assertTrue(response.indexOf("user=null") > 0);
|
assertTrue(response.indexOf("user=null") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
assertTrue(response.indexOf("user=null") > 0);
|
assertTrue(response.indexOf("user=null") > 0);
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
assertTrue(response.indexOf("user=admin") > 0);
|
assertTrue(response.indexOf("user=admin") > 0);
|
||||||
|
|
|
@ -78,6 +78,9 @@ public class PropertyUserStoreTest
|
||||||
|
|
||||||
store.start();
|
store.start();
|
||||||
|
|
||||||
|
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("tom"));
|
||||||
|
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("dick"));
|
||||||
|
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("harry"));
|
||||||
Assert.assertEquals(3,userCount.get());
|
Assert.assertEquals(3,userCount.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +120,11 @@ public class PropertyUserStoreTest
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000)
|
while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000)
|
||||||
|
{
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertNotNull("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip"));
|
||||||
Assert.assertEquals(4,userCount.get());
|
Assert.assertEquals(4,userCount.get());
|
||||||
|
|
||||||
Assert.assertTrue(users.contains("skip"));
|
Assert.assertTrue(users.contains("skip"));
|
||||||
|
|
|
@ -112,5 +112,11 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>1.8.5</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -7,12 +7,18 @@ import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||||
import org.eclipse.jetty.io.Connection;
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
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.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
public class AsyncHttpConnection extends HttpConnection
|
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 static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
|
||||||
|
private int _total_no_progress;
|
||||||
|
|
||||||
public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
|
public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
|
||||||
{
|
{
|
||||||
|
@ -21,22 +27,23 @@ public class AsyncHttpConnection extends HttpConnection
|
||||||
|
|
||||||
public Connection handle() throws IOException
|
public Connection handle() throws IOException
|
||||||
{
|
{
|
||||||
|
LOG.debug("handle {}",this);
|
||||||
Connection connection = this;
|
Connection connection = this;
|
||||||
|
boolean some_progress=false;
|
||||||
|
boolean progress=true;
|
||||||
|
|
||||||
// Loop while more in buffer
|
// Loop while more in buffer
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setCurrentConnection(this);
|
setCurrentConnection(this);
|
||||||
|
|
||||||
boolean progress=true;
|
|
||||||
boolean more_in_buffer =false;
|
boolean more_in_buffer =false;
|
||||||
|
|
||||||
while (_endp.isOpen() && (more_in_buffer || progress))
|
while (_endp.isOpen() && (more_in_buffer || progress) && connection==this)
|
||||||
{
|
{
|
||||||
progress=false;
|
progress=false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOG.debug("async request",_request);
|
|
||||||
|
|
||||||
// Handle resumed request
|
// Handle resumed request
|
||||||
if (_request._async.isAsync() && !_request._async.isComplete())
|
if (_request._async.isAsync() && !_request._async.isComplete())
|
||||||
|
@ -88,7 +95,7 @@ public class AsyncHttpConnection extends HttpConnection
|
||||||
{
|
{
|
||||||
_parser.reset();
|
_parser.reset();
|
||||||
_generator.reset(true);
|
_generator.reset(true);
|
||||||
return switched;
|
connection=switched;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +105,6 @@ public class AsyncHttpConnection extends HttpConnection
|
||||||
reset(false);
|
reset(false);
|
||||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// else Are we suspended?
|
// else Are we suspended?
|
||||||
else if (_request.isAsyncStarted())
|
else if (_request.isAsyncStarted())
|
||||||
{
|
{
|
||||||
|
@ -108,6 +114,8 @@ public class AsyncHttpConnection extends HttpConnection
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||||
|
|
||||||
|
some_progress|=progress|((SelectChannelEndPoint)_endp).isProgressing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,10 +125,36 @@ public class AsyncHttpConnection extends HttpConnection
|
||||||
_parser.returnBuffers();
|
_parser.returnBuffers();
|
||||||
|
|
||||||
// Are we write blocked
|
// Are we write blocked
|
||||||
if (_generator.isCommitted() && !_generator.isComplete())
|
if (_generator.isCommitted() && !_generator.isComplete() && _endp.isOpen())
|
||||||
((AsyncEndPoint)_endp).scheduleWrite();
|
((AsyncEndPoint)_endp).scheduleWrite();
|
||||||
else
|
else
|
||||||
_generator.returnBuffers();
|
_generator.returnBuffers();
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
LOG.info("EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||||
|
|
||||||
|
LOG.setDebugEnabled(true);
|
||||||
|
Log.getLogger("org.eclipse.jetty.io.nio").getLogger("ssl").setDebugEnabled(true);
|
||||||
|
Log.getLogger(ChannelEndPoint.class).setDebugEnabled(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NO_PROGRESS_CLOSE>0 && _total_no_progress>NO_PROGRESS_CLOSE)
|
||||||
|
{
|
||||||
|
LOG.warn("Closing EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||||
|
_endp.close();
|
||||||
|
if (_endp instanceof SelectChannelEndPoint)
|
||||||
|
{
|
||||||
|
System.err.println(((SelectChannelEndPoint)_endp).getSelectManager().dump());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.debug("unhandle {}",this);
|
||||||
}
|
}
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,8 @@ public class BlockingHttpConnection extends HttpConnection
|
||||||
LOG.debug(e);
|
LOG.debug(e);
|
||||||
}
|
}
|
||||||
_generator.sendError(e.getStatus(), e.getReason(), null, true);
|
_generator.sendError(e.getStatus(), e.getReason(), null, true);
|
||||||
|
|
||||||
_parser.reset();
|
_parser.reset();
|
||||||
_endp.close();
|
_endp.shutdownOutput();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -205,6 +205,7 @@ public class Dispatcher implements RequestDispatcher
|
||||||
if (!(response instanceof HttpServletResponse))
|
if (!(response instanceof HttpServletResponse))
|
||||||
response = new ServletResponseHttpWrapper(response);
|
response = new ServletResponseHttpWrapper(response);
|
||||||
|
|
||||||
|
final boolean old_handled=baseRequest.isHandled();
|
||||||
final String old_uri=baseRequest.getRequestURI();
|
final String old_uri=baseRequest.getRequestURI();
|
||||||
final String old_context_path=baseRequest.getContextPath();
|
final String old_context_path=baseRequest.getContextPath();
|
||||||
final String old_servlet_path=baseRequest.getServletPath();
|
final String old_servlet_path=baseRequest.getServletPath();
|
||||||
|
@ -216,6 +217,7 @@ public class Dispatcher implements RequestDispatcher
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
baseRequest.setHandled(false);
|
||||||
baseRequest.setDispatcherType(dispatch);
|
baseRequest.setDispatcherType(dispatch);
|
||||||
|
|
||||||
if (_named!=null)
|
if (_named!=null)
|
||||||
|
@ -262,6 +264,8 @@ public class Dispatcher implements RequestDispatcher
|
||||||
|
|
||||||
baseRequest.setRequestURI(_uri);
|
baseRequest.setRequestURI(_uri);
|
||||||
baseRequest.setContextPath(_contextHandler.getContextPath());
|
baseRequest.setContextPath(_contextHandler.getContextPath());
|
||||||
|
baseRequest.setServletPath(null);
|
||||||
|
baseRequest.setPathInfo(_uri);
|
||||||
baseRequest.setAttributes(attr);
|
baseRequest.setAttributes(attr);
|
||||||
|
|
||||||
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||||
|
@ -286,6 +290,7 @@ public class Dispatcher implements RequestDispatcher
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
baseRequest.setHandled(old_handled);
|
||||||
baseRequest.setRequestURI(old_uri);
|
baseRequest.setRequestURI(old_uri);
|
||||||
baseRequest.setContextPath(old_context_path);
|
baseRequest.setContextPath(old_context_path);
|
||||||
baseRequest.setServletPath(old_servlet_path);
|
baseRequest.setServletPath(old_servlet_path);
|
||||||
|
|
|
@ -327,7 +327,7 @@ public abstract class HttpConnection extends AbstractConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_in == null)
|
if (_in == null)
|
||||||
_in = new HttpInput(((HttpParser)_parser),_connector.getMaxIdleTime());
|
_in = new HttpInput(HttpConnection.this);
|
||||||
return _in;
|
return _in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +677,16 @@ public abstract class HttpConnection extends AbstractConnection
|
||||||
return _expect102Processing;
|
return _expect102Processing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public int getMaxIdleTime()
|
||||||
|
{
|
||||||
|
if (_connector.isLowResources() && _endp.getMaxIdleTime()==_connector.getMaxIdleTime())
|
||||||
|
return _connector.getLowResourceMaxIdleTime();
|
||||||
|
if (_endp.getMaxIdleTime()>0)
|
||||||
|
return _endp.getMaxIdleTime();
|
||||||
|
return _connector.getMaxIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -966,8 +976,7 @@ public abstract class HttpConnection extends AbstractConnection
|
||||||
{
|
{
|
||||||
Output()
|
Output()
|
||||||
{
|
{
|
||||||
super((AbstractGenerator)HttpConnection.this._generator,
|
super(HttpConnection.this);
|
||||||
_connector.isLowResources()?_connector.getLowResourceMaxIdleTime():_connector.getMaxIdleTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -22,14 +22,14 @@ import org.eclipse.jetty.io.Buffer;
|
||||||
|
|
||||||
public class HttpInput extends ServletInputStream
|
public class HttpInput extends ServletInputStream
|
||||||
{
|
{
|
||||||
|
protected final HttpConnection _connection;
|
||||||
protected final HttpParser _parser;
|
protected final HttpParser _parser;
|
||||||
protected final long _maxIdleTime;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public HttpInput(HttpParser parser, long maxIdleTime)
|
public HttpInput(HttpConnection connection)
|
||||||
{
|
{
|
||||||
_parser=parser;
|
_connection=connection;
|
||||||
_maxIdleTime=maxIdleTime;
|
_parser=(HttpParser)connection.getParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -40,7 +40,7 @@ public class HttpInput extends ServletInputStream
|
||||||
public int read() throws IOException
|
public int read() throws IOException
|
||||||
{
|
{
|
||||||
int c=-1;
|
int c=-1;
|
||||||
Buffer content=_parser.blockForContent(_maxIdleTime);
|
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
|
||||||
if (content!=null)
|
if (content!=null)
|
||||||
c= 0xff & content.get();
|
c= 0xff & content.get();
|
||||||
return c;
|
return c;
|
||||||
|
@ -54,7 +54,7 @@ public class HttpInput extends ServletInputStream
|
||||||
public int read(byte[] b, int off, int len) throws IOException
|
public int read(byte[] b, int off, int len) throws IOException
|
||||||
{
|
{
|
||||||
int l=-1;
|
int l=-1;
|
||||||
Buffer content=_parser.blockForContent(_maxIdleTime);
|
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
|
||||||
if (content!=null)
|
if (content!=null)
|
||||||
l= content.get(b, off, len);
|
l= content.get(b, off, len);
|
||||||
return l;
|
return l;
|
||||||
|
|
|
@ -36,9 +36,8 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||||
*/
|
*/
|
||||||
public class HttpOutput extends ServletOutputStream
|
public class HttpOutput extends ServletOutputStream
|
||||||
{
|
{
|
||||||
|
protected final HttpConnection _connection;
|
||||||
protected final AbstractGenerator _generator;
|
protected final AbstractGenerator _generator;
|
||||||
protected final long _maxIdleTime;
|
|
||||||
protected final ByteArrayBuffer _buf = new ByteArrayBuffer(AbstractGenerator.NO_BYTES);
|
|
||||||
private boolean _closed;
|
private boolean _closed;
|
||||||
|
|
||||||
// These are held here for reuse by Writer
|
// These are held here for reuse by Writer
|
||||||
|
@ -46,15 +45,20 @@ public class HttpOutput extends ServletOutputStream
|
||||||
Writer _converter;
|
Writer _converter;
|
||||||
char[] _chars;
|
char[] _chars;
|
||||||
ByteArrayOutputStream2 _bytes;
|
ByteArrayOutputStream2 _bytes;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public HttpOutput(AbstractGenerator generator, long maxIdleTime)
|
public HttpOutput(HttpConnection connection)
|
||||||
{
|
{
|
||||||
_generator=generator;
|
_connection=connection;
|
||||||
_maxIdleTime=maxIdleTime;
|
_generator=(AbstractGenerator)connection.getGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public int getMaxIdleTime()
|
||||||
|
{
|
||||||
|
return _connection.getMaxIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public boolean isWritten()
|
public boolean isWritten()
|
||||||
{
|
{
|
||||||
|
@ -87,7 +91,7 @@ public class HttpOutput extends ServletOutputStream
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException
|
public void flush() throws IOException
|
||||||
{
|
{
|
||||||
_generator.flush(_maxIdleTime);
|
_generator.flush(getMaxIdleTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -122,7 +126,7 @@ public class HttpOutput extends ServletOutputStream
|
||||||
// Block until we can add _content.
|
// Block until we can add _content.
|
||||||
while (_generator.isBufferFull())
|
while (_generator.isBufferFull())
|
||||||
{
|
{
|
||||||
_generator.blockForOutput(_maxIdleTime);
|
_generator.blockForOutput(getMaxIdleTime());
|
||||||
if (_closed)
|
if (_closed)
|
||||||
throw new IOException("Closed");
|
throw new IOException("Closed");
|
||||||
if (!_generator.isOpen())
|
if (!_generator.isOpen())
|
||||||
|
@ -152,7 +156,7 @@ public class HttpOutput extends ServletOutputStream
|
||||||
// Block until we can add _content.
|
// Block until we can add _content.
|
||||||
while (_generator.isBufferFull())
|
while (_generator.isBufferFull())
|
||||||
{
|
{
|
||||||
_generator.blockForOutput(_maxIdleTime);
|
_generator.blockForOutput(getMaxIdleTime());
|
||||||
if (_closed)
|
if (_closed)
|
||||||
throw new IOException("Closed");
|
throw new IOException("Closed");
|
||||||
if (!_generator.isOpen())
|
if (!_generator.isOpen())
|
||||||
|
@ -175,7 +179,7 @@ public class HttpOutput extends ServletOutputStream
|
||||||
// Block until our buffer is free
|
// Block until our buffer is free
|
||||||
while (buffer.length() > 0 && _generator.isOpen())
|
while (buffer.length() > 0 && _generator.isOpen())
|
||||||
{
|
{
|
||||||
_generator.blockForOutput(_maxIdleTime);
|
_generator.blockForOutput(getMaxIdleTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,12 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||||
import org.eclipse.jetty.io.Connection;
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
public class LocalConnector extends AbstractConnector
|
public class LocalConnector extends AbstractConnector
|
||||||
{
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(LocalConnector.class);
|
||||||
private final BlockingQueue<Request> _requests = new LinkedBlockingQueue<Request>();
|
private final BlockingQueue<Request> _requests = new LinkedBlockingQueue<Request>();
|
||||||
|
|
||||||
public LocalConnector()
|
public LocalConnector()
|
||||||
|
@ -135,8 +138,14 @@ public class LocalConnector extends AbstractConnector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (IOException x)
|
||||||
|
{
|
||||||
|
LOG.debug(x);
|
||||||
|
leaveOpen = false;
|
||||||
|
}
|
||||||
catch (Exception x)
|
catch (Exception x)
|
||||||
{
|
{
|
||||||
|
LOG.warn(x);
|
||||||
leaveOpen = false;
|
leaveOpen = false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
@ -202,79 +202,36 @@ public class Request implements HttpServletRequest
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Extract Paramters from query string and/or form _content.
|
* Extract Parameters from query string and/or form _content.
|
||||||
*/
|
*/
|
||||||
public void extractParameters()
|
public void extractParameters()
|
||||||
{
|
{
|
||||||
if (_baseParameters == null)
|
if (_baseParameters == null)
|
||||||
_baseParameters = new MultiMap(16);
|
_baseParameters = new MultiMap(16);
|
||||||
|
|
||||||
if (_paramsExtracted)
|
if (_paramsExtracted)
|
||||||
{
|
{
|
||||||
if (_parameters==null)
|
if (_parameters==null)
|
||||||
_parameters=_baseParameters;
|
_parameters=_baseParameters;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_paramsExtracted = true;
|
_paramsExtracted = true;
|
||||||
|
|
||||||
// Handle query string
|
try
|
||||||
if (_uri!=null && _uri.hasQuery())
|
|
||||||
{
|
{
|
||||||
if (_queryEncoding==null)
|
// Handle query string
|
||||||
_uri.decodeQueryTo(_baseParameters);
|
if (_uri!=null && _uri.hasQuery())
|
||||||
else
|
|
||||||
{
|
{
|
||||||
try
|
if (_queryEncoding==null)
|
||||||
{
|
_uri.decodeQueryTo(_baseParameters);
|
||||||
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
|
else
|
||||||
}
|
|
||||||
catch (UnsupportedEncodingException e)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.warn(e);
|
|
||||||
else
|
|
||||||
LOG.warn(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle any _content.
|
|
||||||
String encoding = getCharacterEncoding();
|
|
||||||
String content_type = getContentType();
|
|
||||||
if (content_type != null && content_type.length() > 0)
|
|
||||||
{
|
|
||||||
content_type = HttpFields.valueParameters(content_type, null);
|
|
||||||
|
|
||||||
if (MimeTypes.FORM_ENCODED.equalsIgnoreCase(content_type) && _inputState==__NONE &&
|
|
||||||
(HttpMethods.POST.equals(getMethod()) || HttpMethods.PUT.equals(getMethod())))
|
|
||||||
{
|
|
||||||
int content_length = getContentLength();
|
|
||||||
if (content_length != 0)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int maxFormContentSize=-1;
|
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
|
||||||
|
|
||||||
if (_context!=null)
|
|
||||||
maxFormContentSize=_context.getContextHandler().getMaxFormContentSize();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
|
||||||
if (size!=null)
|
|
||||||
maxFormContentSize =size.intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content_length>maxFormContentSize && maxFormContentSize > 0)
|
|
||||||
{
|
|
||||||
throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize);
|
|
||||||
}
|
|
||||||
InputStream in = getInputStream();
|
|
||||||
|
|
||||||
// Add form params to query params
|
|
||||||
UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1);
|
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (UnsupportedEncodingException e)
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
|
@ -283,23 +240,75 @@ public class Request implements HttpServletRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// handle any _content.
|
||||||
if (_parameters==null)
|
String encoding = getCharacterEncoding();
|
||||||
_parameters=_baseParameters;
|
String content_type = getContentType();
|
||||||
else if (_parameters!=_baseParameters)
|
if (content_type != null && content_type.length() > 0)
|
||||||
{
|
|
||||||
// Merge parameters (needed if parameters extracted after a forward).
|
|
||||||
Iterator iter = _baseParameters.entrySet().iterator();
|
|
||||||
while (iter.hasNext())
|
|
||||||
{
|
{
|
||||||
Map.Entry entry = (Map.Entry)iter.next();
|
content_type = HttpFields.valueParameters(content_type, null);
|
||||||
String name=(String)entry.getKey();
|
|
||||||
Object values=entry.getValue();
|
if (MimeTypes.FORM_ENCODED.equalsIgnoreCase(content_type) && _inputState==__NONE &&
|
||||||
for (int i=0;i<LazyList.size(values);i++)
|
(HttpMethods.POST.equals(getMethod()) || HttpMethods.PUT.equals(getMethod())))
|
||||||
_parameters.add(name, LazyList.get(values, i));
|
{
|
||||||
|
int content_length = getContentLength();
|
||||||
|
if (content_length != 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int maxFormContentSize=-1;
|
||||||
|
|
||||||
|
if (_context!=null)
|
||||||
|
maxFormContentSize=_context.getContextHandler().getMaxFormContentSize();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
||||||
|
if (size!=null)
|
||||||
|
maxFormContentSize =size.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_length>maxFormContentSize && maxFormContentSize > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize);
|
||||||
|
}
|
||||||
|
InputStream in = getInputStream();
|
||||||
|
|
||||||
|
// Add form params to query params
|
||||||
|
UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.warn(e);
|
||||||
|
else
|
||||||
|
LOG.warn(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (_parameters==null)
|
||||||
|
_parameters=_baseParameters;
|
||||||
|
else if (_parameters!=_baseParameters)
|
||||||
|
{
|
||||||
|
// Merge parameters (needed if parameters extracted after a forward).
|
||||||
|
Iterator iter = _baseParameters.entrySet().iterator();
|
||||||
|
while (iter.hasNext())
|
||||||
|
{
|
||||||
|
Map.Entry entry = (Map.Entry)iter.next();
|
||||||
|
String name=(String)entry.getKey();
|
||||||
|
Object values=entry.getValue();
|
||||||
|
for (int i=0;i<LazyList.size(values);i++)
|
||||||
|
_parameters.add(name, LazyList.get(values, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//ensure params always set (even if empty) after extraction
|
||||||
|
if (_parameters==null)
|
||||||
|
_parameters=_baseParameters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -431,7 +431,7 @@ public class Response implements HttpServletResponse
|
||||||
if (!canonical.equals(path))
|
if (!canonical.equals(path))
|
||||||
{
|
{
|
||||||
buf = _connection.getRequest().getRootURL();
|
buf = _connection.getRequest().getRootURL();
|
||||||
buf.append(canonical);
|
buf.append(URIUtil.encodePath(canonical));
|
||||||
if (uri.getQuery()!=null)
|
if (uri.getQuery()!=null)
|
||||||
{
|
{
|
||||||
buf.append('?');
|
buf.append('?');
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -251,6 +252,12 @@ public class SocketConnector extends AbstractConnector
|
||||||
try{close();}
|
try{close();}
|
||||||
catch(IOException e2){LOG.ignore(e2);}
|
catch(IOException e2){LOG.ignore(e2);}
|
||||||
}
|
}
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
LOG.debug("EOF", e);
|
||||||
|
try{close();}
|
||||||
|
catch(IOException e2){LOG.ignore(e2);}
|
||||||
|
}
|
||||||
catch (HttpException e)
|
catch (HttpException e)
|
||||||
{
|
{
|
||||||
LOG.debug("BAD", e);
|
LOG.debug("BAD", e);
|
||||||
|
|
|
@ -833,7 +833,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
||||||
String old_path_info = null;
|
String old_path_info = null;
|
||||||
ClassLoader old_classloader = null;
|
ClassLoader old_classloader = null;
|
||||||
Thread current_thread = null;
|
Thread current_thread = null;
|
||||||
String pathInfo = null;
|
String pathInfo = target;
|
||||||
|
|
||||||
DispatcherType dispatch = baseRequest.getDispatcherType();
|
DispatcherType dispatch = baseRequest.getDispatcherType();
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ public class GzipHandler extends HandlerWrapper
|
||||||
*
|
*
|
||||||
* @return the buffer size
|
* @return the buffer size
|
||||||
*/
|
*/
|
||||||
public int setBufferSize()
|
public int getBufferSize()
|
||||||
{
|
{
|
||||||
return _bufferSize;
|
return _bufferSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
||||||
import org.eclipse.jetty.io.Buffer;
|
import org.eclipse.jetty.io.Buffer;
|
||||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||||
import org.eclipse.jetty.io.WriterOutputStream;
|
import org.eclipse.jetty.io.WriterOutputStream;
|
||||||
|
import org.eclipse.jetty.server.Dispatcher;
|
||||||
import org.eclipse.jetty.server.HttpConnection;
|
import org.eclipse.jetty.server.HttpConnection;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Response;
|
import org.eclipse.jetty.server.Response;
|
||||||
|
@ -45,7 +46,7 @@ import org.eclipse.jetty.util.resource.Resource;
|
||||||
*
|
*
|
||||||
* This handle will serve static content and handle If-Modified-Since headers.
|
* This handle will serve static content and handle If-Modified-Since headers.
|
||||||
* No caching is done.
|
* No caching is done.
|
||||||
* Requests that cannot be handled are let pass (Eg no 404's)
|
* Requests for resources that do not exist are let pass (Eg no 404's).
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @org.apache.xbean.XBean
|
* @org.apache.xbean.XBean
|
||||||
|
@ -205,7 +206,7 @@ public class ResourceHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-default.css"));
|
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
|
||||||
}
|
}
|
||||||
catch(IOException e)
|
catch(IOException e)
|
||||||
{
|
{
|
||||||
|
@ -292,10 +293,29 @@ public class ResourceHandler extends AbstractHandler
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected Resource getResource(HttpServletRequest request) throws MalformedURLException
|
protected Resource getResource(HttpServletRequest request) throws MalformedURLException
|
||||||
{
|
{
|
||||||
String path_info=request.getPathInfo();
|
String servletPath;
|
||||||
if (path_info==null)
|
String pathInfo;
|
||||||
return null;
|
Boolean included = request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI) != null;
|
||||||
return getResource(path_info);
|
if (included != null && included.booleanValue())
|
||||||
|
{
|
||||||
|
servletPath = (String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
|
||||||
|
pathInfo = (String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
|
||||||
|
|
||||||
|
if (servletPath == null && pathInfo == null)
|
||||||
|
{
|
||||||
|
servletPath = request.getServletPath();
|
||||||
|
pathInfo = request.getPathInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
included = Boolean.FALSE;
|
||||||
|
servletPath = request.getServletPath();
|
||||||
|
pathInfo = request.getPathInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
|
||||||
|
return getResource(pathInContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -326,7 +346,7 @@ public class ResourceHandler extends AbstractHandler
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/*
|
/*
|
||||||
* @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
|
* @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
|
||||||
*/
|
*/
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
|
@ -334,17 +354,21 @@ public class ResourceHandler extends AbstractHandler
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boolean skipContentBody = false;
|
boolean skipContentBody = false;
|
||||||
|
|
||||||
if(!HttpMethods.GET.equals(request.getMethod()))
|
if(!HttpMethods.GET.equals(request.getMethod()))
|
||||||
{
|
{
|
||||||
if(!HttpMethods.HEAD.equals(request.getMethod()))
|
if(!HttpMethods.HEAD.equals(request.getMethod()))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
skipContentBody = true;
|
skipContentBody = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource resource = getResource(request);
|
Resource resource = getResource(request);
|
||||||
|
|
||||||
if (resource==null || !resource.exists())
|
if (resource==null || !resource.exists())
|
||||||
{
|
{
|
||||||
if (target.endsWith("/jetty-stylesheet.css"))
|
if (target.endsWith("/jetty-dir.css"))
|
||||||
{
|
{
|
||||||
response.setContentType("text/css");
|
response.setContentType("text/css");
|
||||||
resource = getStylesheet();
|
resource = getStylesheet();
|
||||||
|
@ -359,7 +383,7 @@ public class ResourceHandler extends AbstractHandler
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are going to server something
|
// We are going to serve something
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
|
|
||||||
if (resource.isDirectory())
|
if (resource.isDirectory())
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 2009-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.server.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. If _exitJvm ist set to true a hard System.exit() call is being
|
||||||
|
* made.
|
||||||
|
*
|
||||||
|
* This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* Server server = new Server(8080);
|
||||||
|
* HandlerList handlers = new HandlerList();
|
||||||
|
* handlers.setHandlers(new Handler[]
|
||||||
|
* { someOtherHandler, new ShutdownHandler(server,"secret password") });
|
||||||
|
* server.setHandler(handlers);
|
||||||
|
* server.start();
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class ShutdownHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(ShutdownHandler.class);
|
||||||
|
|
||||||
|
private final String _shutdownToken;
|
||||||
|
|
||||||
|
private final Server _server;
|
||||||
|
|
||||||
|
private boolean _exitJvm = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a listener that lets the server be shut down remotely (but only from localhost).
|
||||||
|
*
|
||||||
|
* @param server
|
||||||
|
* the Jetty instance that should be shut down
|
||||||
|
* @param shutdownToken
|
||||||
|
* a secret password to avoid unauthorized shutdown attempts
|
||||||
|
*/
|
||||||
|
public ShutdownHandler(Server server, String shutdownToken)
|
||||||
|
{
|
||||||
|
this._server = server;
|
||||||
|
this._shutdownToken = shutdownToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
if (!target.equals("/shutdown"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.getMethod().equals("POST"))
|
||||||
|
{
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!hasCorrectSecurityToken(request))
|
||||||
|
{
|
||||||
|
LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!requestFromLocalhost(request))
|
||||||
|
{
|
||||||
|
LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("Shutting down by request from " + getRemoteAddr(request));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
shutdownServer();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Shutting down server",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean requestFromLocalhost(HttpServletRequest request)
|
||||||
|
{
|
||||||
|
return "127.0.0.1".equals(getRemoteAddr(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRemoteAddr(HttpServletRequest request)
|
||||||
|
{
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCorrectSecurityToken(HttpServletRequest request)
|
||||||
|
{
|
||||||
|
return _shutdownToken.equals(request.getParameter("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutdownServer() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
|
||||||
|
if (_exitJvm)
|
||||||
|
{
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExitJvm(boolean exitJvm)
|
||||||
|
{
|
||||||
|
this._exitJvm = exitJvm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -133,6 +133,12 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
||||||
super.persist(endpoint);
|
super.persist(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public SelectorManager getSelectorManager()
|
||||||
|
{
|
||||||
|
return _manager;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public Object getConnection()
|
public Object getConnection()
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
package org.eclipse.jetty.server.session;
|
package org.eclipse.jetty.server.session;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -46,6 +48,34 @@ public class HashSessionIdManager extends AbstractSessionIdManager
|
||||||
super(random);
|
super(random);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return Collection of String session IDs
|
||||||
|
*/
|
||||||
|
public Collection<String> getSessions()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableCollection(_sessions.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return Collection of Sessions for the passed session ID
|
||||||
|
*/
|
||||||
|
public Collection<HttpSession> getSession(String id)
|
||||||
|
{
|
||||||
|
ArrayList<HttpSession> sessions = new ArrayList<HttpSession>();
|
||||||
|
Set<WeakReference<HttpSession>> refs =_sessions.get(id);
|
||||||
|
if (refs!=null)
|
||||||
|
{
|
||||||
|
for (WeakReference<HttpSession> ref: refs)
|
||||||
|
{
|
||||||
|
HttpSession session = ref.get();
|
||||||
|
if (session!=null)
|
||||||
|
sessions.add(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Get the session ID with any worker ID.
|
/** Get the session ID with any worker ID.
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.io.InputStream;
|
||||||
import java.sql.Blob;
|
import java.sql.Blob;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DatabaseMetaData;
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.Driver;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
@ -56,6 +57,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
||||||
|
|
||||||
protected final HashSet<String> _sessionIds = new HashSet<String>();
|
protected final HashSet<String> _sessionIds = new HashSet<String>();
|
||||||
protected Server _server;
|
protected Server _server;
|
||||||
|
protected Driver _driver;
|
||||||
protected String _driverClassName;
|
protected String _driverClassName;
|
||||||
protected String _connectionUrl;
|
protected String _connectionUrl;
|
||||||
protected DataSource _datasource;
|
protected DataSource _datasource;
|
||||||
|
@ -184,6 +186,19 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
||||||
_connectionUrl=connectionUrl;
|
_connectionUrl=connectionUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure jdbc connection information via a jdbc Driver
|
||||||
|
*
|
||||||
|
* @param driverClass
|
||||||
|
* @param connectionUrl
|
||||||
|
*/
|
||||||
|
public void setDriverInfo (Driver driverClass, String connectionUrl)
|
||||||
|
{
|
||||||
|
_driver=driverClass;
|
||||||
|
_connectionUrl=connectionUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getDriverClassName()
|
public String getDriverClassName()
|
||||||
{
|
{
|
||||||
return _driverClassName;
|
return _driverClassName;
|
||||||
|
@ -461,7 +476,11 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
||||||
InitialContext ic = new InitialContext();
|
InitialContext ic = new InitialContext();
|
||||||
_datasource = (DataSource)ic.lookup(_jndiName);
|
_datasource = (DataSource)ic.lookup(_jndiName);
|
||||||
}
|
}
|
||||||
else if (_driverClassName!=null && _connectionUrl!=null)
|
else if ( _driver != null && _connectionUrl != null )
|
||||||
|
{
|
||||||
|
DriverManager.registerDriver(_driver);
|
||||||
|
}
|
||||||
|
else if (_driverClassName != null && _connectionUrl != null)
|
||||||
{
|
{
|
||||||
Class.forName(_driverClassName);
|
Class.forName(_driverClassName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ package org.eclipse.jetty.server.ssl;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
|
@ -36,7 +38,6 @@ import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||||
import org.eclipse.jetty.server.HttpConnection;
|
import org.eclipse.jetty.server.HttpConnection;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +98,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
||||||
SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
|
SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
|
||||||
SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
|
SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
|
||||||
SSLSession sslSession=sslEngine.getSession();
|
SSLSession sslSession=sslEngine.getSession();
|
||||||
|
|
||||||
SslCertificates.customize(sslSession,endpoint,request);
|
SslCertificates.customize(sslSession,endpoint,request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,33 +566,19 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
||||||
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
|
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
|
||||||
{
|
{
|
||||||
SSLEngine engine;
|
SSLEngine engine;
|
||||||
if (channel != null && _sslContextFactory.isSessionCachingEnabled())
|
if (channel != null)
|
||||||
{
|
{
|
||||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||||
int peerPort = channel.socket().getPort();
|
int peerPort = channel.socket().getPort();
|
||||||
engine = _sslContextFactory.getSslContext().createSSLEngine(peerHost, peerPort);
|
engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
engine = _sslContextFactory.getSslContext().createSSLEngine();
|
engine = _sslContextFactory.newSslEngine();
|
||||||
}
|
}
|
||||||
customizeEngine(engine);
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private void customizeEngine(SSLEngine engine)
|
|
||||||
{
|
|
||||||
engine.setUseClientMode(false);
|
engine.setUseClientMode(false);
|
||||||
|
return engine;
|
||||||
if (_sslContextFactory.getWantClientAuth())
|
|
||||||
engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
|
||||||
if (_sslContextFactory.getNeedClientAuth())
|
|
||||||
engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
|
||||||
|
|
||||||
engine.setEnabledCipherSuites(
|
|
||||||
_sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
|
|
||||||
engine.getSupportedCipherSuites()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -601,22 +588,13 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (!_sslContextFactory.checkConfig())
|
_sslContextFactory.checkKeyStore();
|
||||||
{
|
|
||||||
throw new IllegalStateException("SSL context is not configured correctly.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_sslContextFactory.start();
|
_sslContextFactory.start();
|
||||||
|
|
||||||
SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
|
SSLEngine sslEngine = _sslContextFactory.newSslEngine();
|
||||||
|
|
||||||
sslEngine.setUseClientMode(false);
|
sslEngine.setUseClientMode(false);
|
||||||
sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
|
||||||
sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
|
||||||
|
|
||||||
sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
|
|
||||||
sslEngine.getEnabledCipherSuites(),
|
|
||||||
sslEngine.getSupportedCipherSuites()));
|
|
||||||
|
|
||||||
SSLSession sslSession = sslEngine.getSession();
|
SSLSession sslSession = sslEngine.getSession();
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import javax.net.ssl.SSLSocket;
|
||||||
import org.eclipse.jetty.http.HttpSchemes;
|
import org.eclipse.jetty.http.HttpSchemes;
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
import org.eclipse.jetty.io.RuntimeIOException;
|
||||||
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||||
|
@ -67,6 +68,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
||||||
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
|
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
public SslSocketConnector(SslContextFactory sslContextFactory)
|
public SslSocketConnector(SslContextFactory sslContextFactory)
|
||||||
{
|
{
|
||||||
_sslContextFactory = sslContextFactory;
|
_sslContextFactory = sslContextFactory;
|
||||||
|
@ -329,6 +331,22 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
||||||
return integralPort == 0 || integralPort == request.getServerPort();
|
return integralPort == 0 || integralPort == request.getServerPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
public void open() throws IOException
|
||||||
|
{
|
||||||
|
_sslContextFactory.checkKeyStore();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_sslContextFactory.start();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeIOException(e);
|
||||||
|
}
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
|
@ -336,11 +354,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (!_sslContextFactory.checkConfig())
|
_sslContextFactory.checkKeyStore();
|
||||||
{
|
|
||||||
throw new IllegalStateException("SSL context is not configured correctly.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_sslContextFactory.start();
|
_sslContextFactory.start();
|
||||||
|
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
@ -372,22 +386,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
||||||
@Override
|
@Override
|
||||||
protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
|
protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
|
||||||
{
|
{
|
||||||
SSLServerSocketFactory factory = _sslContextFactory.getSslContext().getServerSocketFactory();
|
return _sslContextFactory.newSslServerSocket(host,port,backlog);
|
||||||
|
|
||||||
SSLServerSocket socket =
|
|
||||||
(SSLServerSocket) (host==null ?
|
|
||||||
factory.createServerSocket(port,backlog):
|
|
||||||
factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
|
|
||||||
|
|
||||||
if (_sslContextFactory.getWantClientAuth())
|
|
||||||
socket.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
|
||||||
if (_sslContextFactory.getNeedClientAuth())
|
|
||||||
socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
|
||||||
|
|
||||||
socket.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
|
|
||||||
socket.getEnabledCipherSuites(),
|
|
||||||
socket.getSupportedCipherSuites()));
|
|
||||||
return socket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -52,7 +52,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
||||||
{
|
{
|
||||||
int x=write++&0xff;
|
int x=write++&0xff;
|
||||||
if (x<8)
|
if (x<8)
|
||||||
|
{
|
||||||
|
clearWritable();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (x<32)
|
if (x<32)
|
||||||
return flush(header);
|
return flush(header);
|
||||||
return super.flush(header,buffer,trailer);
|
return super.flush(header,buffer,trailer);
|
||||||
|
@ -67,7 +70,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
||||||
{
|
{
|
||||||
int x=write++&0xff;
|
int x=write++&0xff;
|
||||||
if (x<8)
|
if (x<8)
|
||||||
|
{
|
||||||
|
clearWritable();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (x<32)
|
if (x<32)
|
||||||
{
|
{
|
||||||
View v = new View(buffer);
|
View v = new View(buffer);
|
||||||
|
@ -75,6 +81,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
||||||
int l=super.flush(v);
|
int l=super.flush(v);
|
||||||
if (l>0)
|
if (l>0)
|
||||||
buffer.skip(l);
|
buffer.skip(l);
|
||||||
|
clearWritable();
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
return super.flush(buffer);
|
return super.flush(buffer);
|
||||||
|
|
|
@ -45,6 +45,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleWithRequest10() throws Exception
|
public void testMaxIdleWithRequest10() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleWithRequest10");
|
||||||
configureServer(new HelloWorldHandler());
|
configureServer(new HelloWorldHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
@ -76,6 +77,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleWithRequest11() throws Exception
|
public void testMaxIdleWithRequest11() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleWithRequest11");
|
||||||
configureServer(new EchoHandler());
|
configureServer(new EchoHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
@ -110,6 +112,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleNoRequest() throws Exception
|
public void testMaxIdleNoRequest() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleNoRequest");
|
||||||
configureServer(new EchoHandler());
|
configureServer(new EchoHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
@ -138,6 +141,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleWithSlowRequest() throws Exception
|
public void testMaxIdleWithSlowRequest() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleWithSlowRequest");
|
||||||
configureServer(new EchoHandler());
|
configureServer(new EchoHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
@ -178,6 +182,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleWithSlowResponse() throws Exception
|
public void testMaxIdleWithSlowResponse() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleWithSlowResponse");
|
||||||
configureServer(new SlowResponseHandler());
|
configureServer(new SlowResponseHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
@ -207,6 +212,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||||
@Test
|
@Test
|
||||||
public void testMaxIdleWithWait() throws Exception
|
public void testMaxIdleWithWait() throws Exception
|
||||||
{
|
{
|
||||||
|
System.err.println("testMaxIdleWithWait");
|
||||||
configureServer(new WaitHandler());
|
configureServer(new WaitHandler());
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(10000);
|
||||||
|
|
|
@ -425,7 +425,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
|
|
||||||
while(len>=0)
|
while(len>=0)
|
||||||
{
|
{
|
||||||
Thread.sleep(500);
|
Thread.sleep(100);
|
||||||
len=is.read(buf);
|
len=is.read(buf);
|
||||||
if (len>0)
|
if (len>0)
|
||||||
total+=len;
|
total+=len;
|
||||||
|
@ -447,6 +447,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
|
|
||||||
long start=System.currentTimeMillis();
|
long start=System.currentTimeMillis();
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
|
int total=0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OutputStream os=client.getOutputStream();
|
OutputStream os=client.getOutputStream();
|
||||||
|
@ -461,7 +462,6 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
).getBytes());
|
).getBytes());
|
||||||
os.flush();
|
os.flush();
|
||||||
|
|
||||||
int total=0;
|
|
||||||
int len=0;
|
int len=0;
|
||||||
byte[] buf=new byte[1024*32];
|
byte[] buf=new byte[1024*32];
|
||||||
|
|
||||||
|
@ -480,6 +480,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
System.err.println("Got "+total+" of "+(512*1024));
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,17 +491,17 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
configureServer(new BigBlockHandler());
|
configureServer(new BigBlockHandler());
|
||||||
|
|
||||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||||
client.setSoTimeout(10000);
|
client.setSoTimeout(20000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OutputStream os=client.getOutputStream();
|
OutputStream os=client.getOutputStream();
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
||||||
|
|
||||||
os.write((
|
os.write((
|
||||||
"GET / HTTP/1.1\r\n"+
|
"GET /r1 HTTP/1.1\r\n"+
|
||||||
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"GET / HTTP/1.1\r\n"+
|
"GET /r2 HTTP/1.1\r\n"+
|
||||||
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
||||||
"connection: close\r\n"+
|
"connection: close\r\n"+
|
||||||
"\r\n"
|
"\r\n"
|
||||||
|
@ -583,6 +584,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler that sends big blocks of data in each of 10 writes, and then sends the time it took for each big block.
|
||||||
protected static class BigBlockHandler extends AbstractHandler
|
protected static class BigBlockHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
@ -598,10 +600,12 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
||||||
long[] times=new long[10];
|
long[] times=new long[10];
|
||||||
for (int i=0;i<times.length;i++)
|
for (int i=0;i<times.length;i++)
|
||||||
{
|
{
|
||||||
|
// System.err.println("\nBLOCK "+request.getRequestURI()+" "+i);
|
||||||
long start=System.currentTimeMillis();
|
long start=System.currentTimeMillis();
|
||||||
out.write(buf);
|
out.write(buf);
|
||||||
long end=System.currentTimeMillis();
|
long end=System.currentTimeMillis();
|
||||||
times[i]=end-start;
|
times[i]=end-start;
|
||||||
|
// System.err.println("Block "+request.getRequestURI()+" "+i+" "+times[i]);
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
for (long t : times)
|
for (long t : times)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.eclipse.jetty.io.Buffer;
|
||||||
import org.eclipse.jetty.io.Buffers;
|
import org.eclipse.jetty.io.Buffers;
|
||||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||||
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.SimpleBuffers;
|
import org.eclipse.jetty.io.SimpleBuffers;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
|
@ -75,7 +76,17 @@ public class HttpWriterTest
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpOutput httpOut = new HttpOutput(generator,60000);
|
HttpConnection connection = new HttpConnection(null,endp,new Server(),null,generator,null)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Connection handle() throws IOException
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
endp.setMaxIdleTime(60000);
|
||||||
|
|
||||||
|
HttpOutput httpOut = new HttpOutput(connection);
|
||||||
_writer = new HttpWriter(httpOut);
|
_writer = new HttpWriter(httpOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +169,17 @@ public class HttpWriterTest
|
||||||
|
|
||||||
hb.setResponse(200,"OK");
|
hb.setResponse(200,"OK");
|
||||||
|
|
||||||
HttpOutput output = new HttpOutput(hb,10000);
|
HttpConnection connection = new HttpConnection(null,endp,new Server(),null,hb,null)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Connection handle() throws IOException
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
endp.setMaxIdleTime(10000);
|
||||||
|
hb.setSendServerVersion(false);
|
||||||
|
HttpOutput output = new HttpOutput(connection);
|
||||||
HttpWriter writer = new HttpWriter(output);
|
HttpWriter writer = new HttpWriter(output);
|
||||||
writer.setCharacterEncoding(StringUtil.__UTF8);
|
writer.setCharacterEncoding(StringUtil.__UTF8);
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,16 @@ import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
@ -68,7 +72,50 @@ public class RequestTest
|
||||||
_server.stop();
|
_server.stop();
|
||||||
_server.join();
|
_server.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParamExtraction() throws Exception
|
||||||
|
{
|
||||||
|
_handler._checker = new RequestTester()
|
||||||
|
{
|
||||||
|
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||||
|
{
|
||||||
|
Map map = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//do the parse
|
||||||
|
request.getParameterMap();
|
||||||
|
Assert.fail("Expected parsing failure");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
//catch the error and check the param map is not null
|
||||||
|
map = request.getParameterMap();
|
||||||
|
assertFalse(map == null);
|
||||||
|
assertTrue(map.isEmpty());
|
||||||
|
|
||||||
|
Enumeration names = request.getParameterNames();
|
||||||
|
assertFalse(names.hasMoreElements());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Send a request with query string with illegal hex code to cause
|
||||||
|
//an exception parsing the params
|
||||||
|
String request="GET /?param=%ZZaaa HTTP/1.1\r\n"+
|
||||||
|
"Host: whatever\r\n"+
|
||||||
|
"Content-Type: text/html;charset=utf8\n"+
|
||||||
|
"\n";
|
||||||
|
|
||||||
|
String response = _connector.getResponses(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContentTypeEncoding() throws Exception
|
public void testContentTypeEncoding() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -383,31 +383,45 @@ public class ResponseTest
|
||||||
public void testSendRedirect()
|
public void testSendRedirect()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
|
String[][] tests={
|
||||||
HttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
|
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
|
||||||
Response response = new Response(connection);
|
{"/other/location","http://myhost:8888/other/location"},
|
||||||
Request request = connection.getRequest();
|
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||||
request.setServerName("myhost");
|
{"location","http://myhost:8888/path/location"},
|
||||||
request.setServerPort(8888);
|
{"./location","http://myhost:8888/path/location"},
|
||||||
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
{"../location","http://myhost:8888/location"},
|
||||||
request.setContextPath("/path");
|
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||||
request.setRequestedSessionId("12345");
|
{"l%20cation","http://myhost:8888/path/l%20cation"},
|
||||||
request.setRequestedSessionIdFromCookie(false);
|
{"./l%20cation","http://myhost:8888/path/l%20cation"},
|
||||||
AbstractSessionManager manager=new HashSessionManager();
|
{"../l%20cation","http://myhost:8888/l%20cation"},
|
||||||
manager.setSessionIdManager(new HashSessionIdManager());
|
};
|
||||||
request.setSessionManager(manager);
|
|
||||||
request.setSession(new TestSession(manager,"12345"));
|
for (int i=1;i<tests.length;i++)
|
||||||
manager.setCheckingRemoteSessionIdEncoding(false);
|
{
|
||||||
|
ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
|
||||||
|
HttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
|
||||||
|
Response response = new Response(connection);
|
||||||
|
Request request = connection.getRequest();
|
||||||
|
request.setServerName("myhost");
|
||||||
|
request.setServerPort(8888);
|
||||||
|
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
||||||
|
request.setContextPath("/path");
|
||||||
|
request.setRequestedSessionId("12345");
|
||||||
|
request.setRequestedSessionIdFromCookie(i>0);
|
||||||
|
AbstractSessionManager manager=new HashSessionManager();
|
||||||
|
manager.setSessionIdManager(new HashSessionIdManager());
|
||||||
|
request.setSessionManager(manager);
|
||||||
|
request.setSession(new TestSession(manager,"12345"));
|
||||||
|
manager.setCheckingRemoteSessionIdEncoding(false);
|
||||||
|
|
||||||
response.sendRedirect("/other/location");
|
response.sendRedirect(tests[i][0]);
|
||||||
|
|
||||||
String location = out.getOut().toString();
|
String location = out.getOut().toString();
|
||||||
int l=location.indexOf("Location: ");
|
int l=location.indexOf("Location: ");
|
||||||
int e=location.indexOf('\n',l);
|
int e=location.indexOf('\n',l);
|
||||||
location=location.substring(l+10,e).trim();
|
location=location.substring(l+10,e).trim();
|
||||||
|
assertEquals(tests[i][0],tests[i][1],location);
|
||||||
assertEquals("http://myhost:8888/other/location;jsessionid=12345",location);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class StressTest
|
||||||
_server.setThreadPool(_threads);
|
_server.setThreadPool(_threads);
|
||||||
|
|
||||||
_connector = new SelectChannelConnector();
|
_connector = new SelectChannelConnector();
|
||||||
_connector.setAcceptors(Math.max(1, Runtime.getRuntime().availableProcessors() / 2));
|
_connector.setAcceptors(1);
|
||||||
_connector.setAcceptQueueSize(5000);
|
_connector.setAcceptQueueSize(5000);
|
||||||
_connector.setMaxIdleTime(30000);
|
_connector.setMaxIdleTime(30000);
|
||||||
_server.addConnector(_connector);
|
_server.addConnector(_connector);
|
||||||
|
@ -123,7 +123,7 @@ public class StressTest
|
||||||
// TODO needs to be further investigated
|
// TODO needs to be further investigated
|
||||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||||
|
|
||||||
doThreads(10,100,false);
|
doThreads(10,10,false);
|
||||||
if (Stress.isEnabled())
|
if (Stress.isEnabled())
|
||||||
{
|
{
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
@ -139,7 +139,7 @@ public class StressTest
|
||||||
// TODO needs to be further investigated
|
// TODO needs to be further investigated
|
||||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||||
|
|
||||||
doThreads(20,100,true);
|
doThreads(20,10,true);
|
||||||
if (Stress.isEnabled())
|
if (Stress.isEnabled())
|
||||||
{
|
{
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package org.eclipse.jetty.server.handler;
|
||||||
|
//========================================================================
|
||||||
|
//Copyright (c) 1999-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.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.toolchain.test.SimpleRequest;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource Handler test
|
||||||
|
*
|
||||||
|
* TODO: increase the testing going on here
|
||||||
|
*/
|
||||||
|
public class ResourceHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
private static Server _server;
|
||||||
|
private static Connector _connector;
|
||||||
|
private static ContextHandler _contextHandler;
|
||||||
|
private static ResourceHandler _resourceHandler;
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
_server = new Server();
|
||||||
|
_connector = new SocketConnector();
|
||||||
|
_server.setConnectors(new Connector[] { _connector });
|
||||||
|
|
||||||
|
_resourceHandler = new ResourceHandler();
|
||||||
|
|
||||||
|
_contextHandler = new ContextHandler("/resource");
|
||||||
|
_contextHandler.setHandler(_resourceHandler);
|
||||||
|
_server.setHandler(_contextHandler);
|
||||||
|
_server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@AfterClass
|
||||||
|
public void tearDown() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
_resourceHandler.setResourceBase(MavenTestingUtils.getTestResourceDir("simple").getAbsolutePath());
|
||||||
|
|
||||||
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
|
|
||||||
|
Assert.assertEquals("simple text", sr.getString("/resource/simple.txt"));
|
||||||
|
|
||||||
|
Assert.assertNotNull("missing jetty.css" , sr.getString("/resource/jetty-dir.css"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.eclipse.jetty.server.handler;
|
||||||
|
|
||||||
|
//========================================================================
|
||||||
|
//Copyright (c) 2009-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.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
public class ShutdownHandlerTest
|
||||||
|
{
|
||||||
|
@Mock private HttpServletRequest request;
|
||||||
|
@Mock private HttpServletResponse response;
|
||||||
|
|
||||||
|
private Server server = new Server(0);
|
||||||
|
private String shutdownToken = "asdlnsldgnklns";
|
||||||
|
|
||||||
|
// class under test
|
||||||
|
private ShutdownHandler shutdownHandler;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void startServer() throws Exception
|
||||||
|
{
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
server.start();
|
||||||
|
shutdownHandler = new ShutdownHandler(server,shutdownToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shutdownServerWithCorrectTokenAndIPTest() throws Exception
|
||||||
|
{
|
||||||
|
setDefaultExpectations();
|
||||||
|
shutdownHandler.handle("/shutdown",null,request,response);
|
||||||
|
assertEquals("Server should be stopped","STOPPED",server.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wrongTokenTest() throws Exception
|
||||||
|
{
|
||||||
|
setDefaultExpectations();
|
||||||
|
when(request.getParameter("token")).thenReturn("anothertoken");
|
||||||
|
shutdownHandler.handle("/shutdown",null,request,response);
|
||||||
|
assertEquals("Server should be running","STARTED",server.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shutdownRequestNotFromLocalhostTest() throws Exception
|
||||||
|
{
|
||||||
|
setDefaultExpectations();
|
||||||
|
when(request.getRemoteAddr()).thenReturn("192.168.3.3");
|
||||||
|
shutdownHandler.handle("/shutdown",null,request,response);
|
||||||
|
assertEquals("Server should be running","STARTED",server.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultExpectations()
|
||||||
|
{
|
||||||
|
when(request.getMethod()).thenReturn("POST");
|
||||||
|
when(request.getParameter("token")).thenReturn(shutdownToken);
|
||||||
|
when(request.getRemoteAddr()).thenReturn("127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
//========================================================================
|
||||||
|
//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
//Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
//you may not use this file except in compliance with the License.
|
||||||
|
//You may obtain a copy of the License at
|
||||||
|
//http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//Unless required by applicable law or agreed to in writing, software
|
||||||
|
//distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//See the License for the specific language governing permissions and
|
||||||
|
//limitations under the License.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
// JettyTest.java --
|
||||||
|
//
|
||||||
|
// Junit test that shows the Jetty SSL bug.
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server.ssl;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpServer Tester.
|
||||||
|
*/
|
||||||
|
public class SSLCloseTest extends TestCase
|
||||||
|
{
|
||||||
|
private static SslSelectChannelEndPoint __endp;
|
||||||
|
private static class CredulousTM implements TrustManager, X509TrustManager
|
||||||
|
{
|
||||||
|
public X509Certificate[] getAcceptedIssuers()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final TrustManager[] s_dummyTrustManagers=new TrustManager[] { new CredulousTM() };
|
||||||
|
|
||||||
|
// ~ Methods
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed the server the entire request at once.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void testClose() throws Exception
|
||||||
|
{
|
||||||
|
Server server=new Server();
|
||||||
|
SslSelectChannelConnector connector=new SslSelectChannelConnector();
|
||||||
|
|
||||||
|
String keystore = System.getProperty("user.dir")+File.separator+"src"+File.separator+"test"+File.separator+"resources"+File.separator+"keystore";
|
||||||
|
|
||||||
|
connector.setPort(0);
|
||||||
|
connector.setKeystore(keystore);
|
||||||
|
connector.setPassword("storepwd");
|
||||||
|
connector.setKeyPassword("keypwd");
|
||||||
|
|
||||||
|
server.setConnectors(new Connector[]
|
||||||
|
{ connector });
|
||||||
|
server.setHandler(new WriteHandler());
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
|
||||||
|
SSLContext ctx=SSLContext.getInstance("SSLv3");
|
||||||
|
ctx.init(null,s_dummyTrustManagers,new java.security.SecureRandom());
|
||||||
|
|
||||||
|
int port=connector.getLocalPort();
|
||||||
|
|
||||||
|
// System.err.println("write:"+i);
|
||||||
|
Socket socket=ctx.getSocketFactory().createSocket("localhost",port);
|
||||||
|
OutputStream os=socket.getOutputStream();
|
||||||
|
|
||||||
|
os.write("GET /test HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n".getBytes());
|
||||||
|
os.flush();
|
||||||
|
|
||||||
|
BufferedReader in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
|
||||||
|
String line;
|
||||||
|
while ((line=in.readLine())!=null)
|
||||||
|
{
|
||||||
|
System.err.println(line);
|
||||||
|
if (line.trim().length()==0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(2000);
|
||||||
|
System.err.println(__endp);
|
||||||
|
|
||||||
|
while ((line=in.readLine())!=null)
|
||||||
|
System.err.println(line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class WriteHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
response.setStatus(200);
|
||||||
|
response.setHeader("test","value");
|
||||||
|
__endp=(SslSelectChannelEndPoint)baseRequest.getConnection().getEndPoint();
|
||||||
|
|
||||||
|
OutputStream out=response.getOutputStream();
|
||||||
|
|
||||||
|
String data = "Now is the time for all good men to come to the aid of the party.\n";
|
||||||
|
data+="How now brown cow.\n";
|
||||||
|
data+="The quick brown fox jumped over the lazy dog.\n";
|
||||||
|
// data=data+data+data+data+data+data+data+data+data+data+data+data+data;
|
||||||
|
// data=data+data+data+data+data+data+data+data+data+data+data+data+data;
|
||||||
|
data=data+data+data+data;
|
||||||
|
byte[] bytes=data.getBytes("UTF-8");
|
||||||
|
|
||||||
|
for (int i=0;i<2;i++)
|
||||||
|
{
|
||||||
|
System.err.println("Write "+i+" "+bytes.length);
|
||||||
|
out.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(RuntimeException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch(Error e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch(Throwable e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -133,7 +133,7 @@ public class SSLEngineTest
|
||||||
@Test
|
@Test
|
||||||
public void testBigResponse() throws Exception
|
public void testBigResponse() throws Exception
|
||||||
{
|
{
|
||||||
SSLContext ctx=SSLContext.getInstance("SSLv3");
|
SSLContext ctx=SSLContext.getInstance("TLS");
|
||||||
ctx.init(null,s_dummyTrustManagers,new java.security.SecureRandom());
|
ctx.init(null,s_dummyTrustManagers,new java.security.SecureRandom());
|
||||||
|
|
||||||
int port=connector.getLocalPort();
|
int port=connector.getLocalPort();
|
||||||
|
@ -367,4 +367,5 @@ public class SSLEngineTest
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import javax.net.ssl.TrustManagerFactory;
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.server.HttpServerTestBase;
|
import org.eclipse.jetty.server.HttpServerTestBase;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HttpServer Tester.
|
* HttpServer Tester.
|
||||||
|
@ -60,14 +61,14 @@ public class SslSelectChannelServerTest extends HttpServerTestBase
|
||||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init(keystore);
|
trustManagerFactory.init(keystore);
|
||||||
__sslContext = SSLContext.getInstance("SSL");
|
__sslContext = SSLContext.getInstance("TLS");
|
||||||
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpsURLConnection.setDefaultHostnameVerifier(__hostnameverifier);
|
HttpsURLConnection.setDefaultHostnameVerifier(__hostnameverifier);
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
SSLContext sc = SSLContext.getInstance("TLS");
|
||||||
sc.init(null, __trustAllCerts, new java.security.SecureRandom());
|
sc.init(null, __trustAllCerts, new java.security.SecureRandom());
|
||||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||||
}
|
}
|
||||||
|
@ -79,5 +80,20 @@ public class SslSelectChannelServerTest extends HttpServerTestBase
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
public void testBlockingWhileWritingResponseContent() throws Exception
|
||||||
|
{
|
||||||
|
super.testBlockingWhileWritingResponseContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
public void testBigBlocks() throws Exception
|
||||||
|
{
|
||||||
|
super.testBigBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import javax.net.ssl.TrustManagerFactory;
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.server.ConnectorTimeoutTest;
|
import org.eclipse.jetty.server.ConnectorTimeoutTest;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
||||||
{
|
{
|
||||||
|
@ -57,4 +58,12 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoProgress() throws Exception
|
||||||
|
{
|
||||||
|
testMaxIdleNoRequest();
|
||||||
|
super.testMaxIdleWithSlowRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,10 @@ package org.eclipse.jetty.server.ssl;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||||
|
@ -37,7 +39,9 @@ public class SslSocketServerTest extends HttpServerTestBase
|
||||||
@Override
|
@Override
|
||||||
protected Socket newSocket(String host, int port) throws Exception
|
protected Socket newSocket(String host, int port) throws Exception
|
||||||
{
|
{
|
||||||
return __sslContext.getSocketFactory().createSocket(host,port);
|
SSLSocket socket = (SSLSocket)__sslContext.getSocketFactory().createSocket(host,port);
|
||||||
|
socket.setEnabledProtocols(new String[] {"TLSv1"});
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +63,7 @@ public class SslSocketServerTest extends HttpServerTestBase
|
||||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init(keystore);
|
trustManagerFactory.init(keystore);
|
||||||
__sslContext = SSLContext.getInstance("SSL");
|
__sslContext = SSLContext.getInstance("TLSv1");
|
||||||
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.net.Socket;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||||
|
@ -26,12 +27,14 @@ import org.junit.BeforeClass;
|
||||||
|
|
||||||
public class SslSocketTimeoutTest extends ConnectorTimeoutTest
|
public class SslSocketTimeoutTest extends ConnectorTimeoutTest
|
||||||
{
|
{
|
||||||
static SSLContext _sslContext;
|
static SSLContext __sslContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Socket newSocket(String host, int port) throws Exception
|
protected Socket newSocket(String host, int port) throws Exception
|
||||||
{
|
{
|
||||||
return _sslContext.getSocketFactory().createSocket(host,port);
|
SSLSocket socket = (SSLSocket)__sslContext.getSocketFactory().createSocket(host,port);
|
||||||
|
socket.setEnabledProtocols(new String[] {"TLSv1"});
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
|
@ -53,8 +56,8 @@ public class SslSocketTimeoutTest extends ConnectorTimeoutTest
|
||||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init(keystore);
|
trustManagerFactory.init(keystore);
|
||||||
_sslContext = SSLContext.getInstance("SSL");
|
__sslContext = SSLContext.getInstance("TLSv1");
|
||||||
_sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
__sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,17 +159,6 @@ public class SslTruncationAttackTest
|
||||||
Assert.assertTrue("endpoint not closed", endPointClosed.get());
|
Assert.assertTrue("endpoint not closed", endPointClosed.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This test is currently failing because we are looping on SslSCEP.unwrap()
|
|
||||||
* to fill the buffer, so there is a case where we loop once, read some data
|
|
||||||
* loop again and read -1, but we can't close the connection yet as we have
|
|
||||||
* to notify the application (not sure that this is necessary... must assume
|
|
||||||
* the data is truncated, so it's not that safe to pass it to the application).
|
|
||||||
* This case needs to be revisited, and it also requires a review of the
|
|
||||||
* Connection:close case, especially on the client side.
|
|
||||||
* @throws Exception if the test fails
|
|
||||||
*/
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void testTruncationAttackBeforeReading() throws Exception
|
public void testTruncationAttackBeforeReading() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -234,8 +223,8 @@ public class SslTruncationAttackTest
|
||||||
// Sleep for a while to detect eventual spin looping
|
// Sleep for a while to detect eventual spin looping
|
||||||
TimeUnit.SECONDS.sleep(1);
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
|
||||||
|
Assert.assertTrue("endpoint closed", endPointClosed.get());
|
||||||
Assert.assertEquals("handle() invocations", 1, handleCount.get());
|
Assert.assertEquals("handle() invocations", 1, handleCount.get());
|
||||||
Assert.assertTrue("endpoint not closed", endPointClosed.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
simple text
|
|
@ -482,7 +482,6 @@ public class ServletHandler extends ScopedHandler
|
||||||
res = ((ServletResponseHttpWrapper)res).getResponse();
|
res = ((ServletResponseHttpWrapper)res).getResponse();
|
||||||
|
|
||||||
// Do the filter/handling thang
|
// Do the filter/handling thang
|
||||||
baseRequest.setHandled(true);
|
|
||||||
if (chain!=null)
|
if (chain!=null)
|
||||||
chain.doFilter(req, res);
|
chain.doFilter(req, res);
|
||||||
else
|
else
|
||||||
|
@ -591,6 +590,10 @@ public class ServletHandler extends ScopedHandler
|
||||||
else
|
else
|
||||||
LOG.debug("Response already committed for handling ",e);
|
LOG.debug("Response already committed for handling ",e);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -14,27 +14,47 @@
|
||||||
package org.eclipse.jetty.servlet;
|
package org.eclipse.jetty.servlet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.HttpRetryException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.DispatcherType;
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
import javax.servlet.GenericServlet;
|
import javax.servlet.GenericServlet;
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.Servlet;
|
import javax.servlet.Servlet;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletRequestWrapper;
|
import javax.servlet.ServletRequestWrapper;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.ServletResponseWrapper;
|
import javax.servlet.ServletResponseWrapper;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Dispatcher;
|
import org.eclipse.jetty.server.Dispatcher;
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
|
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -44,17 +64,27 @@ public class DispatcherTest
|
||||||
{
|
{
|
||||||
private Server _server;
|
private Server _server;
|
||||||
private LocalConnector _connector;
|
private LocalConnector _connector;
|
||||||
private ServletContextHandler _context;
|
private ContextHandlerCollection _contextCollection;
|
||||||
|
private ServletContextHandler _contextHandler;
|
||||||
|
private ResourceHandler _resourceHandler;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws Exception
|
public void init() throws Exception
|
||||||
{
|
{
|
||||||
_server = new Server();
|
_server = new Server();
|
||||||
_server.setSendServerVersion(false);
|
_server.setSendServerVersion(false);
|
||||||
_connector = new LocalConnector();
|
_connector = new LocalConnector();
|
||||||
_context = new ServletContextHandler();
|
|
||||||
_context.setContextPath("/context");
|
_contextCollection = new ContextHandlerCollection();
|
||||||
_server.setHandler(_context);
|
_contextHandler = new ServletContextHandler();
|
||||||
|
_contextHandler.setContextPath("/context");
|
||||||
|
_contextCollection.addHandler(_contextHandler);
|
||||||
|
_resourceHandler = new ResourceHandler();
|
||||||
|
_resourceHandler.setResourceBase(MavenTestingUtils.getTestResourceDir("dispatchResourceTest").getAbsolutePath());
|
||||||
|
ContextHandler resourceContextHandler = new ContextHandler("/resource");
|
||||||
|
resourceContextHandler.setHandler(_resourceHandler);
|
||||||
|
_contextCollection.addHandler(resourceContextHandler);
|
||||||
|
_server.setHandler(_contextCollection);
|
||||||
_server.addConnector( _connector );
|
_server.addConnector( _connector );
|
||||||
|
|
||||||
_server.start();
|
_server.start();
|
||||||
|
@ -70,8 +100,8 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testForward() throws Exception
|
public void testForward() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
_contextHandler.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
||||||
_context.addServlet(AssertForwardServlet.class, "/AssertForwardServlet/*");
|
_contextHandler.addServlet(AssertForwardServlet.class, "/AssertForwardServlet/*");
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
|
@ -87,8 +117,8 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testInclude() throws Exception
|
public void testInclude() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
_contextHandler.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
||||||
_context.addServlet(AssertIncludeServlet.class, "/AssertIncludeServlet/*");
|
_contextHandler.addServlet(AssertIncludeServlet.class, "/AssertIncludeServlet/*");
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
|
@ -103,9 +133,9 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testForwardThenInclude() throws Exception
|
public void testForwardThenInclude() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
_contextHandler.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
||||||
_context.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
_contextHandler.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
||||||
_context.addServlet(AssertForwardIncludeServlet.class, "/AssertForwardIncludeServlet/*");
|
_contextHandler.addServlet(AssertForwardIncludeServlet.class, "/AssertForwardIncludeServlet/*");
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
|
@ -120,9 +150,9 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testIncludeThenForward() throws Exception
|
public void testIncludeThenForward() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
_contextHandler.addServlet(IncludeServlet.class, "/IncludeServlet/*");
|
||||||
_context.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
_contextHandler.addServlet(ForwardServlet.class, "/ForwardServlet/*");
|
||||||
_context.addServlet(AssertIncludeForwardServlet.class, "/AssertIncludeForwardServlet/*");
|
_contextHandler.addServlet(AssertIncludeForwardServlet.class, "/AssertIncludeForwardServlet/*");
|
||||||
|
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
|
@ -140,8 +170,8 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testServletForward() throws Exception
|
public void testServletForward() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(DispatchServletServlet.class, "/dispatch/*");
|
_contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*");
|
||||||
_context.addServlet(RogerThatServlet.class, "/roger/*");
|
_contextHandler.addServlet(RogerThatServlet.class, "/roger/*");
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
|
@ -157,8 +187,8 @@ public class DispatcherTest
|
||||||
@Test
|
@Test
|
||||||
public void testServletInclude() throws Exception
|
public void testServletInclude() throws Exception
|
||||||
{
|
{
|
||||||
_context.addServlet(DispatchServletServlet.class, "/dispatch/*");
|
_contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*");
|
||||||
_context.addServlet(RogerThatServlet.class, "/roger/*");
|
_contextHandler.addServlet(RogerThatServlet.class, "/roger/*");
|
||||||
|
|
||||||
String expected=
|
String expected=
|
||||||
"HTTP/1.1 200 OK\r\n"+
|
"HTTP/1.1 200 OK\r\n"+
|
||||||
|
@ -171,6 +201,80 @@ public class DispatcherTest
|
||||||
assertEquals(expected, responses);
|
assertEquals(expected, responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkingResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
String responses = _connector.getResponses("GET /resource/content.txt HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
assertTrue(responses.contains("content goes here")); // from inside the context.txt file
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIncludeToResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
|
||||||
|
|
||||||
|
String responses = _connector.getResponses("GET /context/resourceServlet/content.txt?do=include HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
// from inside the context.txt file
|
||||||
|
Assert.assertNotNull(responses);
|
||||||
|
|
||||||
|
assertTrue(responses.contains("content goes here"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testForwardToResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
|
||||||
|
|
||||||
|
String responses = _connector.getResponses("GET /context/resourceServlet/content.txt?do=forward HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
// from inside the context.txt file
|
||||||
|
assertTrue(responses.contains("content goes here"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrappedIncludeToResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
|
||||||
|
|
||||||
|
String responses = _connector.getResponses("GET /context/resourceServlet/content.txt?do=include&wrapped=true HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
// from inside the context.txt file
|
||||||
|
assertTrue(responses.contains("content goes here"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrappedForwardToResourceHandler() throws Exception
|
||||||
|
{
|
||||||
|
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
|
||||||
|
|
||||||
|
String responses = _connector.getResponses("GET /context/resourceServlet/content.txt?do=forward&wrapped=true HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
// from inside the context.txt file
|
||||||
|
assertTrue(responses.contains("content goes here"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testForwardFilterToRogerServlet() throws Exception
|
||||||
|
{
|
||||||
|
_contextHandler.addServlet(RogerThatServlet.class, "/*");
|
||||||
|
_contextHandler.addServlet(ReserveEchoServlet.class,"/recho/*");
|
||||||
|
_contextHandler.addServlet(EchoServlet.class, "/echo/*");
|
||||||
|
_contextHandler.addFilter(ForwardFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||||
|
|
||||||
|
String rogerResponse = _connector.getResponses("GET /context/ HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
String echoResponse = _connector.getResponses("GET /context/foo?echo=echoText HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
String rechoResponse = _connector.getResponses("GET /context/?echo=echoText HTTP/1.0\n" + "Host: localhost\n\n");
|
||||||
|
|
||||||
|
assertTrue(rogerResponse.contains("Roger That!"));
|
||||||
|
assertTrue(echoResponse.contains("echoText"));
|
||||||
|
assertTrue(rechoResponse.contains("txeTohce"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class ForwardServlet extends HttpServlet implements Servlet
|
public static class ForwardServlet extends HttpServlet implements Servlet
|
||||||
{
|
{
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
@ -187,6 +291,59 @@ public class DispatcherTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward filter works with roger, echo and reverse echo servlets to test various
|
||||||
|
* forwarding bits using filters.
|
||||||
|
*
|
||||||
|
* when there is an echo parameter and the path info is / it forwards to the reverse echo
|
||||||
|
* anything else in the pathInfo and it sends straight to the echo servlet...otherwise its
|
||||||
|
* all roger servlet
|
||||||
|
*/
|
||||||
|
public static class ForwardFilter implements Filter
|
||||||
|
{
|
||||||
|
ServletContext servletContext;
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException
|
||||||
|
{
|
||||||
|
servletContext = filterConfig.getServletContext().getContext("/context");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( servletContext == null || !(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse))
|
||||||
|
{
|
||||||
|
chain.doFilter(request,response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServletRequest req = (HttpServletRequest)request;
|
||||||
|
HttpServletResponse resp = (HttpServletResponse)response;
|
||||||
|
|
||||||
|
if ( req.getParameter("echo") != null && "/".equals(req.getPathInfo()))
|
||||||
|
{
|
||||||
|
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("/recho");
|
||||||
|
dispatcher.forward(request,response);
|
||||||
|
}
|
||||||
|
else if ( req.getParameter("echo") != null )
|
||||||
|
{
|
||||||
|
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("/echo");
|
||||||
|
dispatcher.forward(request,response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chain.doFilter(request,response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class DispatchServletServlet extends HttpServlet implements Servlet
|
public static class DispatchServletServlet extends HttpServlet implements Servlet
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -230,6 +387,84 @@ public class DispatcherTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class EchoServlet extends GenericServlet
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
String echoText = req.getParameter("echo");
|
||||||
|
|
||||||
|
if ( echoText == null )
|
||||||
|
{
|
||||||
|
throw new ServletException("echo is a required parameter");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.getWriter().print(echoText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ReserveEchoServlet extends GenericServlet
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
String echoText = req.getParameter("echo");
|
||||||
|
|
||||||
|
if ( echoText == null )
|
||||||
|
{
|
||||||
|
throw new ServletException("echo is a required parameter");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.getWriter().print(new StringBuffer(echoText).reverse().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DispatchToResourceServlet extends HttpServlet implements Servlet
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
ServletContext targetContext = getServletConfig().getServletContext().getContext("/resource");
|
||||||
|
|
||||||
|
RequestDispatcher dispatcher = targetContext.getRequestDispatcher(req.getPathInfo());
|
||||||
|
|
||||||
|
if ( "true".equals(req.getParameter("wrapped")))
|
||||||
|
{
|
||||||
|
if (req.getParameter("do").equals("forward"))
|
||||||
|
{
|
||||||
|
dispatcher.forward(new HttpServletRequestWrapper(req),new HttpServletResponseWrapper(res));
|
||||||
|
}
|
||||||
|
else if (req.getParameter("do").equals("include"))
|
||||||
|
{
|
||||||
|
dispatcher.include(new HttpServletRequestWrapper(req),new HttpServletResponseWrapper(res));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ServletException("type of forward or include is required");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (req.getParameter("do").equals("forward"))
|
||||||
|
{
|
||||||
|
dispatcher.forward(req,res);
|
||||||
|
}
|
||||||
|
else if (req.getParameter("do").equals("include"))
|
||||||
|
{
|
||||||
|
dispatcher.include(req,res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ServletException("type of forward or include is required");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class AssertForwardServlet extends HttpServlet implements Servlet
|
public static class AssertForwardServlet extends HttpServlet implements Servlet
|
||||||
{
|
{
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
content goes here
|
|
@ -0,0 +1 @@
|
||||||
|
text
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue