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:
Jan Bartel 2011-10-04 17:45:15 +11:00
commit 32dbb1bddb
137 changed files with 6215 additions and 3619 deletions

23
.gitignore vendored
View File

@ -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]

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);
} }
} }

View File

@ -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)
{ {

View File

@ -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: ";

View File

@ -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()

View File

@ -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 &amp;&amp; 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();

View File

@ -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 );
}
}

View File

@ -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();

View File

@ -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);
}
}
} }
}); });

View File

@ -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;

View File

@ -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);
}
} }

View File

@ -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

View File

@ -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());
}
}

View File

@ -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();
}
} }

View File

@ -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()
{ {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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();

View File

@ -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;

View File

@ -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()));
}
} }

View File

@ -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;
} }
} }

View File

@ -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 + "]";
} }
} }

View File

@ -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
{} {}
} }

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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());

View File

@ -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
{ {

View File

@ -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

View File

@ -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;
} }

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);
} }
} }

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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>
* *
* &lt;Set name="handler"&gt; * &lt;Set name="handler"&gt;
* &lt;New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"&gt; * &lt;New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"&gt;
* &lt;Set name="rules"&gt; * &lt;Set name="rules"&gt;
* &lt;Array type="org.eclipse.jetty.rewrite.handler.Rule"&gt; * &lt;Array type="org.eclipse.jetty.rewrite.handler.Rule"&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule"&gt; * &lt;New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule"&gt;
* &lt;Set name="pattern"&gt;/*&lt;/Set&gt; * &lt;Set name="pattern"&gt;/*&lt;/Set&gt;
* &lt;Set name="replacement"&gt;/test&lt;/Set&gt; * &lt;Set name="replacement"&gt;/test&lt;/Set&gt;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="rewrite" class="org.eclipse.jetty.rewrite.handler.ProxyRule"&gt;
* &lt;Set name="pattern"&gt;/*&lt;/Set&gt;
* &lt;Set name="proxyTo"&gt;http://webtide.com:8080&lt;/Set&gt;
* &lt;/New&gt;
* &lt;/Item&gt;
*
* &lt;Item&gt;
* &lt;New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule"&gt; * &lt;New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule"&gt;
* &lt;Set name="pattern"&gt;/session/&lt;/Set&gt; * &lt;Set name="pattern"&gt;/session/&lt;/Set&gt;
* &lt;Set name="code"&gt;400&lt;/Set&gt; * &lt;Set name="code"&gt;400&lt;/Set&gt;
@ -75,7 +82,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt; * &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt;
* &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt; * &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt;
* &lt;Set name="name"&gt;server&lt;/Set&gt; * &lt;Set name="name"&gt;server&lt;/Set&gt;
@ -83,7 +90,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt; * &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt;
* &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt; * &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt;
* &lt;Set name="name"&gt;title&lt;/Set&gt; * &lt;Set name="name"&gt;title&lt;/Set&gt;
@ -91,28 +98,28 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule"&gt; * &lt;New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule"&gt;
* &lt;Set name="pattern"&gt;/test/dispatch&lt;/Set&gt; * &lt;Set name="pattern"&gt;/test/dispatch&lt;/Set&gt;
* &lt;Set name="location"&gt;http://jetty.eclipse.org&lt;/Set&gt; * &lt;Set name="location"&gt;http://jetty.eclipse.org&lt;/Set&gt;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule"&gt; * &lt;New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule"&gt;
* &lt;Set name="regex"&gt;/test-jaas/$&lt;/Set&gt; * &lt;Set name="regex"&gt;/test-jaas/$&lt;/Set&gt;
* &lt;Set name="replacement"&gt;/demo&lt;/Set&gt; * &lt;Set name="replacement"&gt;/demo&lt;/Set&gt;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule"&gt; * &lt;New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule"&gt;
* &lt;Set name="header"&gt;X-Forwarded-Scheme&lt;/Set&gt; * &lt;Set name="header"&gt;X-Forwarded-Scheme&lt;/Set&gt;
* &lt;Set name="headerValue"&gt;https&lt;/Set&gt; * &lt;Set name="headerValue"&gt;https&lt;/Set&gt;
* &lt;Set name="scheme"&gt;https&lt;/Set&gt; * &lt;Set name="scheme"&gt;https&lt;/Set&gt;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Item&gt; * &lt;/Item&gt;
* *
* &lt;Item&gt; * &lt;Item&gt;
* &lt;New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer"&gt; * &lt;New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer"&gt;
* *
@ -134,10 +141,10 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Arg&gt; * &lt;/Arg&gt;
* &lt;/Call&gt; * &lt;/Call&gt;
* *
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/ Item&gt; * &lt;/ Item&gt;
* *
* &lt;/Array&gt; * &lt;/Array&gt;
* &lt;/Set&gt; * &lt;/Set&gt;
* *
@ -162,13 +169,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt; * &lt;/New&gt;
* &lt;/Set&gt; * &lt;/Set&gt;
* </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);
} }
} }
} }

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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);
}
} }

View File

@ -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;

View File

@ -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();
} }
} }

View File

@ -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);
}
}
} }
} }
} }

View File

@ -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)

View File

@ -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);

View File

@ -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"));

View File

@ -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>

View File

@ -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;
} }

View File

@ -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
{ {

View File

@ -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);

View File

@ -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());
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -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;

View File

@ -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());
} }
} }

View File

@ -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

View File

@ -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;
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -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('?');

View File

@ -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);

View File

@ -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();

View File

@ -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;
} }

View File

@ -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())

View File

@ -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,&quot;secret password&quot;) });
* 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;
}
}

View File

@ -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()
{ {

View File

@ -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.
* *

View File

@ -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);
} }

View File

@ -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();

View File

@ -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;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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
{ {

View File

@ -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

View File

@ -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);

View File

@ -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"));
}
}

View File

@ -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");
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
} }
} }
} }

View File

@ -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();
}
} }

View File

@ -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();
}
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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());
} }

View File

@ -0,0 +1 @@
simple text

View File

@ -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);
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -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

View File

@ -0,0 +1 @@
content goes here

View File

@ -0,0 +1 @@
text

Some files were not shown because too many files have changed in this diff Show More