Merge branch 'jetty-8' into release-8

This commit is contained in:
Jesse McConnell 2011-10-06 17:30:58 -05:00
commit 8024831fec
154 changed files with 7113 additions and 4012 deletions

23
.gitignore vendored
View File

@ -1,14 +1,33 @@
target/
# eclipse
.classpath
.project
.settings
# maven
target/
*/src/main/java/META-INF/
.pmd
# common junk
*.log
*.swp
*.diff
*.patch
# intellij
*.iml
*.ipr
*.iws
.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-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
+ 350634 Added Resource.newResource(File)
+ 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.
+ 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
+ 352565 cookie httponly flag ignored
+ 353073 better warnings
+ 353285 ServletSecurity annotation ignored
+ 356421 Upgraded websocket to draft 13 support
jetty-7.5.0.v20110901 - 01 September 2011
+ 356421 Upgraded websocket to draft 13 support
+ 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.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
@ -87,9 +88,15 @@ public class LikeJettyXml
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
});
cf.setProtocol("TLSv1.1");
cf.addExcludeProtocols(new String[]{"TLSv1","SSLv3"});
ssl_connector.setStatsOn(true);
server.addConnector(ssl_connector);
ssl_connector.open();
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
ajp.setPort(8009);
server.addConnector(ajp);

View File

@ -29,7 +29,7 @@ public class SecuredHelloHandler
{
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");
server.addBean(loginService);

View File

@ -25,7 +25,7 @@
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includes>META-INF/**,org/eclipse/**</includes>
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
<excludes>**/MANIFEST.MF,javax/**</excludes>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<overWriteReleases>false</overWriteReleases>

View File

@ -22,7 +22,7 @@
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includes>META-INF/**,org/eclipse/**</includes>
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/*</includes>
<excludes>**/MANIFEST.MF,javax/**</excludes>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<overWriteReleases>false</overWriteReleases>
@ -75,6 +75,19 @@
</execution>
</executions>
</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>
</build>

View File

@ -22,7 +22,7 @@
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includes>META-INF/**,org/eclipse/**</includes>
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
<excludes>**/MANIFEST.MF,javax/**</excludes>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<overWriteReleases>false</overWriteReleases>

View File

@ -44,38 +44,38 @@ public class Ajp13Generator extends AbstractGenerator
static
{
byte[] xA001 =
{ (byte) 0xA0, (byte) 0x01 };
{ (byte)0xA0, (byte)0x01 };
byte[] xA002 =
{ (byte) 0xA0, (byte) 0x02 };
{ (byte)0xA0, (byte)0x02 };
byte[] xA003 =
{ (byte) 0xA0, (byte) 0x03 };
{ (byte)0xA0, (byte)0x03 };
byte[] xA004 =
{ (byte) 0xA0, (byte) 0x04 };
{ (byte)0xA0, (byte)0x04 };
byte[] xA005 =
{ (byte) 0xA0, (byte) 0x05 };
{ (byte)0xA0, (byte)0x05 };
byte[] xA006 =
{ (byte) 0xA0, (byte) 0x06 };
{ (byte)0xA0, (byte)0x06 };
byte[] xA007 =
{ (byte) 0xA0, (byte) 0x07 };
{ (byte)0xA0, (byte)0x07 };
byte[] xA008 =
{ (byte) 0xA0, (byte) 0x08 };
{ (byte)0xA0, (byte)0x08 };
byte[] xA009 =
{ (byte) 0xA0, (byte) 0x09 };
{ (byte)0xA0, (byte)0x09 };
byte[] xA00A =
{ (byte) 0xA0, (byte) 0x0A };
{ (byte)0xA0, (byte)0x0A };
byte[] xA00B =
{ (byte) 0xA0, (byte) 0x0B };
__headerHash.put("Content-Type", xA001);
__headerHash.put("Content-Language", xA002);
__headerHash.put("Content-Length", xA003);
__headerHash.put("Date", xA004);
__headerHash.put("Last-Modified", xA005);
__headerHash.put("Location", xA006);
__headerHash.put("Set-Cookie", xA007);
__headerHash.put("Set-Cookie2", xA008);
__headerHash.put("Servlet-Engine", xA009);
__headerHash.put("Status", xA00A);
__headerHash.put("WWW-Authenticate", xA00B);
{ (byte)0xA0, (byte)0x0B };
__headerHash.put("Content-Type",xA001);
__headerHash.put("Content-Language",xA002);
__headerHash.put("Content-Length",xA003);
__headerHash.put("Date",xA004);
__headerHash.put("Last-Modified",xA005);
__headerHash.put("Location",xA006);
__headerHash.put("Set-Cookie",xA007);
__headerHash.put("Set-Cookie2",xA008);
__headerHash.put("Servlet-Engine",xA009);
__headerHash.put("Status",xA00A);
__headerHash.put("WWW-Authenticate",xA00B);
}
@ -83,7 +83,7 @@ public class Ajp13Generator extends AbstractGenerator
// 0, 1 ajp int 1 packet length
// 9 CPONG response Code
private static final byte[] AJP13_CPONG_RESPONSE =
{ 'A', 'B', 0, 1, 9};
{ 'A', 'B', 0, 1, 9 };
private static final byte[] AJP13_END_RESPONSE =
{ 'A', 'B', 0, 2, 5, 1 };
@ -114,7 +114,7 @@ public class Ajp13Generator extends AbstractGenerator
/* ------------------------------------------------------------ */
public Ajp13Generator(Buffers buffers, EndPoint io)
{
super(buffers, io);
super(buffers,io);
}
/* ------------------------------------------------------------ */
@ -130,6 +130,7 @@ public class Ajp13Generator extends AbstractGenerator
{
return true;
}
/* ------------------------------------------------------------ */
@Override
public void reset(boolean returnBuffers)
@ -140,9 +141,7 @@ public class Ajp13Generator extends AbstractGenerator
_needMore = false;
_expectMore = false;
_bufferPrepared = false;
_last=false;
_last = false;
_state = STATE_HEADER;
@ -159,11 +158,9 @@ public class Ajp13Generator extends AbstractGenerator
_noContent = false;
_persistent = true;
_header = null; // Buffer for HTTP header (and maybe small _content)
_buffer = null; // Buffer for copy of passed _content
_content = null; // Buffer passed to addContent
_header = null; // Buffer for HTTP header (and maybe small _content)
_buffer = null; // Buffer for copy of passed _content
_content = null; // Buffer passed to addContent
}
@ -175,13 +172,13 @@ public class Ajp13Generator extends AbstractGenerator
{
initContent();
}
catch(IOException e)
catch (IOException e)
{
throw new RuntimeException(e);
}
return super.getContentBufferSize()-7;
return super.getContentBufferSize() - 7;
}
/* ------------------------------------------------------------ */
@Override
public void increaseContentBufferSize(int contentBufferSize)
@ -196,11 +193,9 @@ public class Ajp13Generator extends AbstractGenerator
* @param content
* @param last
* @throws IllegalArgumentException
* if <code>content</code> is
* {@link Buffer#isImmutable immutable}.
* if <code>content</code> is {@link Buffer#isImmutable immutable}.
* @throws IllegalStateException
* If the request is not expecting any more content, or if the
* buffers are full and cannot be flushed.
* If the request is not expecting any more content, or if the buffers are full and cannot be flushed.
* @throws IOException
* if there is a problem flushing the buffers.
*/
@ -217,13 +212,13 @@ public class Ajp13Generator extends AbstractGenerator
if (_last || _state == STATE_END)
{
LOG.debug("Ignoring extra content {}", content);
LOG.debug("Ignoring extra content {}",content);
content.clear();
return;
}
_last = last;
if(!_endp.isOpen())
if (!_endp.isOpen())
{
_state = STATE_END;
return;
@ -289,8 +284,7 @@ public class Ajp13Generator extends AbstractGenerator
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if(!_endp.isOpen())
if (!_endp.isOpen())
{
_state = STATE_END;
return false;
@ -322,8 +316,7 @@ public class Ajp13Generator extends AbstractGenerator
/* ------------------------------------------------------------ */
/**
* Prepare buffer for unchecked writes. Prepare the generator buffer to
* receive unchecked writes
* Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
*
* @return the available space in the buffer.
* @throws IOException
@ -337,8 +330,7 @@ public class Ajp13Generator extends AbstractGenerator
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if(!_endp.isOpen())
if (!_endp.isOpen())
{
_state = STATE_END;
return -1;
@ -377,8 +369,8 @@ public class Ajp13Generator extends AbstractGenerator
_last = _last | allContentAdded;
boolean has_server = false;
if (_persistent==null)
_persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
if (_persistent == null)
_persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
// get a header buffer
if (_header == null)
@ -390,13 +382,13 @@ public class Ajp13Generator extends AbstractGenerator
try
{
// start the header
_buffer.put((byte) 'A');
_buffer.put((byte) 'B');
_buffer.put((byte)'A');
_buffer.put((byte)'B');
addInt(0);
_buffer.put((byte) 0x4);
_buffer.put((byte)0x4);
addInt(_status);
if (_reason == null)
_reason=HttpGenerator.getReasonBuffer(_status);
_reason = HttpGenerator.getReasonBuffer(_status);
if (_reason == null)
_reason = new ByteArrayBuffer(Integer.toString(_status));
addBuffer(_reason);
@ -407,7 +399,6 @@ public class Ajp13Generator extends AbstractGenerator
_content = null;
}
// allocate 2 bytes for number of headers
int field_index = _buffer.putIndex();
addInt(0);
@ -417,15 +408,15 @@ public class Ajp13Generator extends AbstractGenerator
if (fields != null)
{
// Add headers
int s=fields.size();
for (int f=0;f<s;f++)
int s = fields.size();
for (int f = 0; f < s; f++)
{
HttpFields.Field field = fields.getField(f);
if (field==null)
if (field == null)
continue;
num_fields++;
byte[] codes = (byte[]) __headerHash.get(field.getName());
byte[] codes = (byte[])__headerHash.get(field.getName());
if (codes != null)
{
_buffer.put(codes);
@ -460,14 +451,13 @@ public class Ajp13Generator extends AbstractGenerator
// insert the total packet size on 2nd and 3rd byte that
// was previously
// allocated
addInt(2, payloadSize);
addInt(2,payloadSize);
}
finally
{
_buffer = tmpbuf;
}
_state = STATE_CONTENT;
}
@ -501,7 +491,7 @@ public class Ajp13Generator extends AbstractGenerator
{
try
{
if (_state == STATE_HEADER && !_expectMore)
if (_state == STATE_HEADER && !_expectMore)
throw new IllegalStateException("State==HEADER");
prepareBuffers();
@ -528,90 +518,87 @@ public class Ajp13Generator extends AbstractGenerator
Flushing: while (true)
{
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)
{
case 7:
throw new IllegalStateException(); // should
// never
// happen!
case 6:
len = _endp.flush(_header, _buffer, null);
case 7:
throw new IllegalStateException(); // should
// never
// happen!
case 6:
len = _endp.flush(_header,_buffer,null);
break;
case 5:
throw new IllegalStateException(); // should
// never
// happen!
case 4:
len = _endp.flush(_header);
break;
case 3:
throw new IllegalStateException(); // should
// never
// happen!
case 2:
len = _endp.flush(_buffer);
break;
case 5:
throw new IllegalStateException(); // should
// never
// happen!
case 4:
len = _endp.flush(_header);
break;
case 3:
throw new IllegalStateException(); // should
// never
// happen!
case 2:
len = _endp.flush(_buffer);
break;
case 1:
throw new IllegalStateException(); // should
// never
// happen!
case 0:
{
// Nothing more we can write now.
if (_header != null)
_header.clear();
_bufferPrepared = false;
if (_buffer != null)
break;
case 1:
throw new IllegalStateException(); // should
// never
// happen!
case 0:
{
_buffer.clear();
// Nothing more we can write now.
if (_header != null)
_header.clear();
// reserve some space for the
// header
_buffer.setPutIndex(7);
_buffer.setGetIndex(7);
_bufferPrepared = false;
// 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)
if (_buffer != null)
{
_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;
}
// 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
@ -631,7 +618,7 @@ public class Ajp13Generator extends AbstractGenerator
catch (IOException 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;
_buffer.put((byte) 0);
_buffer.put((byte)0);
int put = _buffer.putIndex();
_buffer.setGetIndex(0);
_buffer.setPutIndex(0);
_buffer.put((byte) 'A');
_buffer.put((byte) 'B');
_buffer.put((byte)'A');
_buffer.put((byte)'B');
addInt(payloadSize + 4);
_buffer.put((byte) 3);
_buffer.put((byte)3);
addInt(payloadSize);
_buffer.setPutIndex(put);
}
@ -759,15 +746,15 @@ public class Ajp13Generator extends AbstractGenerator
/* ------------------------------------------------------------ */
private void addInt(int i)
{
_buffer.put((byte) ((i >> 8) & 0xFF));
_buffer.put((byte) (i & 0xFF));
_buffer.put((byte)((i >> 8) & 0xFF));
_buffer.put((byte)(i & 0xFF));
}
/* ------------------------------------------------------------ */
private void addInt(int startIndex, int i)
{
_buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
_buffer.poke((startIndex + 1), (byte) (i & 0xFF));
_buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
_buffer.poke((startIndex + 1),(byte)(i & 0xFF));
}
/* ------------------------------------------------------------ */
@ -786,7 +773,7 @@ public class Ajp13Generator extends AbstractGenerator
addInt(b.length);
_buffer.put(b);
_buffer.put((byte) 0);
_buffer.put((byte)0);
}
/* ------------------------------------------------------------ */
@ -800,15 +787,14 @@ public class Ajp13Generator extends AbstractGenerator
addInt(b.length());
_buffer.put(b);
_buffer.put((byte) 0);
_buffer.put((byte)0);
}
/* ------------------------------------------------------------ */
public void getBodyChunk() throws IOException
{
_needMore = true;
_expectMore = true;
flushBuffer();
ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
_endp.flush(bf);
}
/* ------------------------------------------------------------ */
@ -818,7 +804,6 @@ public class Ajp13Generator extends AbstractGenerator
_expectMore = false;
}
/* ------------------------------------------------------------ */
public void sendCPong() throws IOException
{
@ -831,13 +816,11 @@ public class Ajp13Generator extends AbstractGenerator
{
_endp.flush(buff);
}
while(buff.length() >0);
while (buff.length() > 0);
_buffers.returnBuffer(buff);
reset(true);
}
}

View File

@ -16,7 +16,6 @@
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
<Item>org.eclipse.jetty.annotations.ContainerInitializerConfiguration</Item>
</Array>
</Arg>
</Call>

View File

@ -18,9 +18,11 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
@ -47,6 +49,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
public void preConfigure(final WebAppContext context) throws Exception
{
@ -58,45 +62,46 @@ public class AnnotationConfiguration extends AbstractConfiguration
boolean metadataComplete = context.getMetaData().isMetaDataComplete();
context.addDecorator(new AnnotationDecorator(context));
if (metadataComplete)
{
//Never scan any jars or classes for annotations if metadata is complete
if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing annotations for context "+context);
return;
}
else
{
//Only scan jars and classes if metadata is not complete and the web app is version 3.0, or
//a 2.5 version webapp that has specifically asked to discover annotations
if (LOG.isDebugEnabled()) LOG.debug("parsing annotations");
AnnotationParser parser = createAnnotationParser();
//Discoverable annotations - those that you have to look for without loading a class
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
parser.registerClassHandler(classHandler);
registerServletContainerInitializerAnnotationHandlers(context, parser);
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
{
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
parseContainerPath(context, parser);
//email from Rajiv Mordani jsrs 315 7 April 2010
// If there is a <others/> then the ordering should be
// WEB-INF/classes the order of the declared elements + others.
// In case there is no others then it is
// WEB-INF/classes + order of the elements.
parseWebInfClasses(context, parser);
parseWebInfLib (context, parser);
}
//save the type inheritance map created by the parser for later reference
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
}
//Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
AnnotationParser parser = null;
if (!metadataComplete)
{
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
{
parser = createAnnotationParser();
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
}
}
else
if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing discoverable servlet annotations for context "+context);
//Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
//classes so we can call their onStartup() methods correctly
List<ServletContainerInitializer> nonExcludedInitializers = getNonExcludedInitializers(context);
parser = registerServletContainerInitializerAnnotationHandlers(context, parser, nonExcludedInitializers);
if (parser != null)
{
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
parseContainerPath(context, parser);
//email from Rajiv Mordani jsrs 315 7 April 2010
// If there is a <others/> then the ordering should be
// WEB-INF/classes the order of the declared elements + others.
// In case there is no others then it is
// WEB-INF/classes + order of the elements.
parseWebInfClasses(context, parser);
parseWebInfLib (context, parser);
}
}
/**
* @return a new AnnotationParser. This method can be overridden to use a different impleemntation of
* the AnnotationParser. Note that this is considered internal API.
@ -112,10 +117,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
context.addDecorator(new AnnotationDecorator(context));
}
public void registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser)
public AnnotationParser registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser, List<ServletContainerInitializer> scis)
throws Exception
{
//TODO verify my interpretation of the spec. That is, that metadata-complete has nothing
//to do with finding the ServletContainerInitializers, classes designated to be of interest to them,
//or even calling them on startup.
@ -125,46 +133,73 @@ public class AnnotationConfiguration extends AbstractConfiguration
//that will record the classes that have that annotation.
//If it is NOT an annotation, then we will interrogate the type hierarchy discovered during
//parsing later on to find the applicable classes.
ArrayList<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
context.setAttribute(ContainerInitializerConfiguration.CONTAINER_INITIALIZERS, initializers);
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
if (loadedInitializers != null)
if (scis == null || scis.isEmpty())
return parser; // nothing to do
ServletContainerInitializerListener listener = new ServletContainerInitializerListener();
listener.setWebAppContext(context);
context.addEventListener(listener);
//may need to add a listener
ArrayList<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
context.setAttribute(CONTAINER_INITIALIZERS, initializers);
for (ServletContainerInitializer service : scis)
{
for (ServletContainerInitializer service : loadedInitializers)
HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
ContainerInitializer initializer = new ContainerInitializer();
initializer.setTarget(service);
initializers.add(initializer);
if (annotation != null)
{
if (!isFromExcludedJar(context, service))
{
HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
ContainerInitializer initializer = new ContainerInitializer();
initializer.setTarget(service);
initializers.add(initializer);
if (annotation != null)
//There is a HandlesTypes annotation on the on the ServletContainerInitializer
Class[] classes = annotation.value();
if (classes != null)
{
initializer.setInterestedTypes(classes);
//We need to create a parser if we haven't already
if (parser == null)
parser = createAnnotationParser();
//If we haven't already done so, we need to register a handler that will
//process the whole class hierarchy
if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
{
Class[] classes = annotation.value();
if (classes != null)
{
initializer.setInterestedTypes(classes);
for (Class c: classes)
{
if (c.isAnnotation())
{
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c));
}
}
}
else
if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
parser.registerClassHandler(classHandler);
}
for (Class c: classes)
{
//The value of one of the HandlesTypes classes is actually an Annotation itself so
//register a handler for it
if (c.isAnnotation())
{
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c));
}
}
else
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
}
else
if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
}
else
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
}
//return the parser in case we lazily created it
return parser;
}
/**
* Check to see if the ServletContainerIntializer loaded via the ServiceLoader came
@ -206,6 +241,30 @@ public class AnnotationConfiguration extends AbstractConfiguration
return !found;
}
public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
throws Exception
{
List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
if (loadedInitializers != null)
{
for (ServletContainerInitializer service : loadedInitializers)
{
if (!isFromExcludedJar(context, service))
nonExcludedInitializers.add(service);
}
}
return nonExcludedInitializers;
}
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
throws Exception
{

View File

@ -1,3 +1,17 @@
package org.eclipse.jetty.annotations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.webapp.WebAppContext;
// ========================================================================
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
@ -11,37 +25,28 @@
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* ContainerInitializerConfiguration
* ServletContainerInitializerListener
*
*
* Apply the ServletContainerInitializers.
*/
public class ContainerInitializerConfiguration extends AbstractConfiguration
public class ServletContainerInitializerListener implements ServletContextListener
{
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
public void preConfigure(WebAppContext context) throws Exception
{
WebAppContext _context = null;
public void setWebAppContext (WebAppContext context)
{
_context = context;
}
public void configure(WebAppContext context) throws Exception
/**
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent sce)
{
List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
MultiMap classMap = (MultiMap)context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
List<ContainerInitializer> initializers = (List<ContainerInitializer>)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
MultiMap classMap = (MultiMap)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
if (initializers != null)
{
@ -58,9 +63,12 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
//add the class with the annotation
i.addApplicableTypeName(name);
//add the classes that inherit the annotation
List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
if (classMap != null)
{
List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
}
}
}
@ -75,29 +83,33 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
{
//add the classes that implement or extend the class.
//TODO but not including the class itself?
List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
if (classMap != null)
{
List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
addInheritedTypes(classMap, i, implementsOrExtends);
}
}
}
}
//instantiate ServletContainerInitializers, call doStart
i.callStartup(context);
try
{
i.callStartup(_context);
}
catch (Exception e)
{
//OK, how do I throw an exception such that it really stops the startup sequence?
e.printStackTrace();
}
}
//TODO Email from Jan Luehe 18 August: after all ServletContainerInitializers have been
//called, need to check to see if there are any ServletRegistrations remaining
//that are "preliminary" and fail the deployment if so.
}
}
public void postConfigure(WebAppContext context) throws Exception
{
}
public void deconfigure(WebAppContext context) throws Exception
{
}
}
@ -114,5 +126,15 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
addInheritedTypes (classMap, initializer, implementsOrExtends);
}
}
/**
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce)
{
// TODO Auto-generated method stub
}
}

View File

@ -178,10 +178,19 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
/* ------------------------------------------------------------ */
/**
* @return the threadPool
* @return the threadpool
*/
public ThreadPool getThreadPool()
{
if (_threadPool==null)
{
QueuedThreadPool pool = new QueuedThreadPool();
pool.setMaxThreads(16);
pool.setDaemon(true);
pool.setName("HttpClient");
_threadPool = pool;
}
return _threadPool;
}
@ -420,13 +429,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
_idleTimeoutQ.setNow();
if (_threadPool == null)
{
QueuedThreadPool pool = new QueuedThreadPool();
pool.setMaxThreads(16);
pool.setDaemon(true);
pool.setName("HttpClient");
_threadPool = pool;
}
getThreadPool();
if (_threadPool instanceof LifeCycle)
{

View File

@ -73,7 +73,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
{
super(endp);
_generator = new HttpGenerator(requestBuffers,endp);
_parser = new HttpParser(responseBuffers,endp,new Handler());
}
@ -277,6 +277,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
{
long filled = _parser.parseAvailable();
io += filled;
if (_parser.isIdle() && (_endp.isInputShutdown() || !_endp.isOpen()))
throw new EOFException();
}
if (io > 0)
@ -353,16 +356,34 @@ public class HttpConnection extends AbstractConnection implements Dumpable
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();
// TODO should not need this
if (!(_parser.isComplete()||_parser.isIdle()))
{
LOG.warn("Incomplete {} {}",_parser,_endp);
if (_exchange!=null && !_exchange.isDone())
{
_exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
_exchange.getEventListener().onException(new EOFException("Incomplete"));
}
}
}
}
if (_generator.isComplete() && !_parser.isComplete())
if (_endp.isInputShutdown() && !_parser.isComplete() && !_parser.isIdle())
{
if (!_endp.isOpen() || _endp.isInputShutdown())
if (_exchange!=null && !_exchange.isDone())
{
complete=true;
close=true;
close();
_exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
_exchange.getEventListener().onException(new EOFException("Incomplete"));
}
_endp.close();
}
if (complete || failed)
@ -431,9 +452,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
finally
{
_parser.returnBuffers();
// 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!
((AsyncEndPoint)_endp).scheduleWrite();
@ -549,6 +570,8 @@ public class HttpConnection extends AbstractConnection implements Dumpable
private boolean shouldClose()
{
if (_endp.isInputShutdown())
return true;
if (_connectionHeader!=null)
{
if (HttpHeaderValues.CLOSE_BUFFER.equals(_connectionHeader))
@ -669,6 +692,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
case HttpExchange.STATUS_EXCEPTED:
case HttpExchange.STATUS_EXPIRED:
break;
case HttpExchange.STATUS_PARSING_CONTENT:
if (_endp.isInputShutdown() && _parser.isState(HttpParser.STATE_EOF_CONTENT))
break;
default:
String exch= exchange.toString();
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
@ -724,7 +750,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
}
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.Dumpable#dump()
@ -746,7 +772,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
AggregateLifeCycle.dump(out,indent,Collections.singletonList(_endp));
}
}
/* ------------------------------------------------------------ */
private class ConnectionIdleTask extends Timeout.Task
{
@ -761,14 +787,14 @@ public class HttpConnection extends AbstractConnection implements Dumpable
}
}
}
/* ------------------------------------------------------------ */
private class NonFinalResponseListener implements HttpEventListener
{
final HttpExchange _exchange;
final HttpEventListener _next;
/* ------------------------------------------------------------ */
public NonFinalResponseListener(HttpExchange exchange)
{
@ -813,7 +839,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
{
_exchange.setEventListener(_next);
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
_parser.reset();
_parser.reset();
}
/* ------------------------------------------------------------ */

View File

@ -584,7 +584,7 @@ public class HttpDestination implements Dumpable
@Override
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()

View File

@ -35,7 +35,9 @@ import org.eclipse.jetty.util.log.Logger;
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:
* <ul>
@ -48,23 +50,25 @@ import org.eclipse.jetty.util.thread.Timeout;
* <li>The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
* </ul>
*
* <p>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
* 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 {@link org.eclipse.jetty.client.CachedExchange}.</p>
* <p>
* 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 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
* {@link org.eclipse.jetty.client.CachedExchange}.
* </p>
*
* <p>Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in
* turn selects a {@link HttpDestination} and calls its {@link HttpDestination#send(HttpExchange)}, which
* then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}.
* A developer may wish to directly call send on the destination or connection if they wish to bypass
* some handling provided (eg Cookie handling in the HttpDestination).</p>
* <p>
* Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in turn selects a {@link HttpDestination} and calls its
* {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}. A
* developer may wish to directly call send on the destination or connection if they wish to bypass some handling provided (eg Cookie handling in the
* HttpDestination).
* </p>
*
* <p>In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed
* pipeline request, authentication retry or redirection). 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>
* <p>
* In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed pipeline request, authentication retry or redirection).
* 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>
*/
public class HttpExchange
{
@ -106,9 +110,10 @@ public class HttpExchange
// a timeout for this exchange
private long _timeout = -1;
private volatile Timeout.Task _timeoutTask;
private long _lastStateChange=-1;
private long _lastStateChange=System.currentTimeMillis();
private long _sent=-1;
private int _lastState=-1;
private int _lastStatePeriod=-1;
boolean _onRequestCompleteDone;
boolean _onResponseCompleteDone;
@ -131,8 +136,10 @@ public class HttpExchange
}
/**
* @param status the status to wait for
* @throws InterruptedException if the waiting thread is interrupted
* @param status
* the status to wait for
* @throws InterruptedException
* if the waiting thread is interrupted
* @deprecated Use {@link #waitForDone()} instead
*/
@Deprecated
@ -142,21 +149,17 @@ public class HttpExchange
}
/**
* 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
* exchange can transit a final state when being used as part
* of a dialog (eg {@link SecurityListener}. Done status
* is thus defined as:<pre>
* done == onConnectionFailed
* || onException
* || onExpire
* || onRequestComplete && onResponseComplete
* 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
* exchange can transit a final state when being used as part of a dialog (eg {@link SecurityListener}. Done status is thus defined as:
*
* <pre>
* done == onConnectionFailed || onException || onExpire || onRequestComplete &amp;&amp; onResponseComplete
* </pre>
*
* @return the done status
* @throws InterruptedException
*/
public int waitForDone () throws InterruptedException
public int waitForDone() throws InterruptedException
{
synchronized (this)
{
@ -170,12 +173,12 @@ public class HttpExchange
{
// TODO - this should do a cancel and wakeup everybody that was waiting.
// might need a version number concept
synchronized(this)
synchronized (this)
{
_timeoutTask=null;
_onRequestCompleteDone=false;
_onResponseCompleteDone=false;
_onDone=false;
_timeoutTask = null;
_onRequestCompleteDone = false;
_onResponseCompleteDone = false;
_onDone = false;
setStatus(STATUS_START);
}
}
@ -186,13 +189,16 @@ public class HttpExchange
{
int oldStatus = _status.get();
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)
_sent=_lastStateChange;
}
// State machine: from which old status you can go into which new status
switch (oldStatus)
{
@ -204,7 +210,10 @@ public class HttpExchange
case STATUS_WAITING_FOR_COMMIT:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -214,11 +223,10 @@ public class HttpExchange
case STATUS_WAITING_FOR_COMMIT:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -228,11 +236,10 @@ public class HttpExchange
case STATUS_SENDING_REQUEST:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -240,16 +247,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_WAITING_FOR_RESPONSE:
if (set=_status.compareAndSet(oldStatus,newStatus))
if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onRequestCommitted();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -259,11 +265,10 @@ public class HttpExchange
case STATUS_PARSING_HEADERS:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -271,16 +276,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_PARSING_CONTENT:
if (set=_status.compareAndSet(oldStatus,newStatus))
if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onResponseHeaderComplete();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -288,16 +292,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_COMPLETED:
if (set=_status.compareAndSet(oldStatus,newStatus))
if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onResponseComplete();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -307,12 +310,12 @@ public class HttpExchange
case STATUS_START:
case STATUS_EXCEPTED:
case STATUS_WAITING_FOR_RESPONSE:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_CANCELLING:
case STATUS_EXPIRED:
// Don't change the status, it's too late
set=true;
set = true;
break;
}
break;
@ -321,12 +324,12 @@ public class HttpExchange
{
case STATUS_EXCEPTED:
case STATUS_CANCELLED:
if (set=_status.compareAndSet(oldStatus,newStatus))
if (set = _status.compareAndSet(oldStatus,newStatus))
done();
break;
default:
// Ignore other statuses, we're cancelling
set=true;
set = true;
break;
}
break;
@ -336,10 +339,10 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_START:
set=_status.compareAndSet(oldStatus,newStatus);
set = _status.compareAndSet(oldStatus,newStatus);
break;
default:
set=true;
set = true;
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()
{
synchronized (this)
@ -369,7 +380,7 @@ public class HttpExchange
* @deprecated
*/
@Deprecated
public boolean isDone (int status)
public boolean isDone(int status)
{
return isDone();
}
@ -381,10 +392,10 @@ public class HttpExchange
public void setEventListener(HttpEventListener listener)
{
_listener=listener;
_listener = listener;
}
public void setTimeout( long timeout )
public void setTimeout(long 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)
{
@ -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)
{
@ -421,8 +434,7 @@ public class HttpExchange
/**
* the local address used by the connection
*
* Note: this method will not be populated unless the exchange
* has been executed by the HttpClient
* Note: this method will not be populated unless the exchange has been executed by the HttpClient
*
* @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)
{
_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)
{
@ -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)
{
@ -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)
{
@ -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)
{
@ -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)
* @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/>
* where:<br/><br/>
* "*" - request applies to server itself<br/>
* where:<br/>
* <br/>
* "*" - request applies to server itself<br/>
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context<br/>
* (this form is generated automatically by HttpClient)<br/>
* abs_path - used for most methods, e.g. /context<br/>
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
* (this form is generated automatically by HttpClient)<br/>
* abs_path - used for most methods, e.g. /context<br/>
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
* <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)
{
_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)
{
if (!uri.isAbsolute())
throw new IllegalArgumentException("!Absolute URI: "+uri);
throw new IllegalArgumentException("!Absolute URI: " + uri);
if (uri.isOpaque())
throw new IllegalArgumentException("Opaque URI: "+uri);
throw new IllegalArgumentException("Opaque URI: " + uri);
LOG.debug("URI = {}",uri.toASCIIString());
String scheme = uri.getScheme();
int port = uri.getPort();
@ -582,13 +605,16 @@ public class HttpExchange
HttpURI httpUri = new HttpURI(uri);
String completePath = httpUri.getCompletePath();
setRequestURI(completePath==null ? "/" : completePath);
setRequestURI(completePath == null?"/":completePath);
}
/**
* 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)
{
@ -597,8 +623,11 @@ public class HttpExchange
/**
* 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)
{
@ -607,30 +636,37 @@ public class HttpExchange
/**
* 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)
{
getRequestFields().put(name, value);
getRequestFields().put(name,value);
}
/**
* 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)
{
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)
{
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)
{
@ -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)
{
@ -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)
{
@ -716,13 +755,10 @@ public class HttpExchange
}
/**
* Initiates the cancelling of this exchange.
* The status of the exchange is set to {@link #STATUS_CANCELLING}.
* Cancelling the exchange is an asynchronous operation with respect to the request/response,
* and as such checking the request/response status of a cancelled exchange may return undefined results
* (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()}.
* Initiates the cancelling of this exchange. The status of the exchange is set to {@link #STATUS_CANCELLING}. Cancelling the exchange is an asynchronous
* operation with respect to the request/response, and as such checking the request/response status of a cancelled exchange may return undefined results
* (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()
{
@ -732,10 +768,10 @@ public class HttpExchange
private void done()
{
synchronized(this)
synchronized (this)
{
disassociate();
_onDone=true;
_onDone = true;
notifyAll();
}
}
@ -764,8 +800,8 @@ public class HttpExchange
void associate(HttpConnection connection)
{
if (connection.getEndPoint().getLocalHost() != null)
_localAddress = new Address(connection.getEndPoint().getLocalHost(), connection.getEndPoint().getLocalPort());
if (connection.getEndPoint().getLocalHost() != null)
_localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
_connection = connection;
if (getStatus() == STATUS_CANCELLING)
@ -789,33 +825,60 @@ public class HttpExchange
public static String toState(int s)
{
String state;
switch(s)
switch (s)
{
case STATUS_START: state="START"; break;
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
case STATUS_WAITING_FOR_COMMIT: state="CONNECTED"; break;
case STATUS_SENDING_REQUEST: state="SENDING"; break;
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";
case STATUS_START:
state = "START";
break;
case STATUS_WAITING_FOR_CONNECTION:
state = "CONNECTING";
break;
case STATUS_WAITING_FOR_COMMIT:
state = "CONNECTED";
break;
case STATUS_SENDING_REQUEST:
state = "SENDING";
break;
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;
}
@Override
public String toString()
{
String state=toState(getStatus());
long now=System.currentTimeMillis();
long forMs = now -_lastStateChange;
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
if (getStatus()>=STATUS_SENDING_REQUEST)
String s= _lastState>=0
?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";
return s;
}
@ -828,79 +891,93 @@ public class HttpExchange
}
/**
* Callback called when the request headers have been sent to the server.
* This implementation does nothing.
* @throws IOException allowed to be thrown by overriding code
* Callback called when the request headers have been sent to the server. This implementation does nothing.
*
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onRequestCommitted() throws IOException
{
}
/**
* Callback called when the request and its body have been sent to the server.
* This implementation does nothing.
* @throws IOException allowed to be thrown by overriding code
* Callback called when the request and its body have been sent to the server. This implementation does nothing.
*
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onRequestComplete() throws IOException
{
}
/**
* Callback called when a response status line has been received from the server.
* This implementation does nothing.
* @param version the HTTP version
* @param status the HTTP status code
* @param reason the HTTP status reason string
* @throws IOException allowed to be thrown by overriding code
* Callback called when a response status line has been received from the server. This implementation does nothing.
*
* @param version
* the HTTP version
* @param status
* 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
{
}
/**
* Callback called for each response header received from the server.
* This implementation does nothing.
* @param name the header name
* @param value the header value
* @throws IOException allowed to be thrown by overriding code
* Callback called for each response header received from the server. This implementation does nothing.
*
* @param name
* the header name
* @param value
* the header value
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
{
}
/**
* Callback called when the response headers have been completely received from the server.
* This implementation does nothing.
* @throws IOException allowed to be thrown by overriding code
* Callback called when the response headers have been completely received from the server. This implementation does nothing.
*
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onResponseHeaderComplete() throws IOException
{
}
/**
* Callback called for each chunk of the response content received from the server.
* This implementation does nothing.
* @param content the buffer holding the content chunk
* @throws IOException allowed to be thrown by overriding code
* Callback called for each chunk of the response content received from the server. This implementation does nothing.
*
* @param content
* the buffer holding the content chunk
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onResponseContent(Buffer content) throws IOException
{
}
/**
* Callback called when the entire response has been received from the server
* This implementation does nothing.
* @throws IOException allowed to be thrown by overriding code
* Callback called when the entire response has been received from the server This implementation does nothing.
*
* @throws IOException
* allowed to be thrown by overriding code
*/
protected void onResponseComplete() throws IOException
{
}
/**
* Callback called when an exception was thrown during an attempt to establish the connection
* with the server (for example the server is not listening).
* Callback called when an exception was thrown during an attempt to establish the connection with the server (for example the server is not listening).
* 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)
{
@ -908,9 +985,10 @@ public class HttpExchange
}
/**
* Callback called when any other exception occurs during the handling of this exchange.
* This implementation logs a warning.
* @param x the exception thrown during the handling of this exchange
* Callback called when any other exception occurs during the handling of this exchange. This implementation logs a warning.
*
* @param x
* the exception thrown during the handling of this exchange
*/
protected void onException(Throwable x)
{
@ -918,8 +996,7 @@ public class HttpExchange
}
/**
* Callback called when no response has been received within the timeout.
* This implementation logs a warning.
* Callback called when no response has been received within the timeout. This implementation logs a warning.
*/
protected void onExpire()
{
@ -927,9 +1004,10 @@ public class HttpExchange
}
/**
* Callback called when the request is retried (due to failures or authentication).
* Implementations must reset any consumable content that needs to be sent.
* @throws IOException allowed to be thrown by overriding code
* Callback called when the request is retried (due to failures or authentication). Implementations must reset any consumable content that needs to be sent.
*
* @throws IOException
* allowed to be thrown by overriding code
*/
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,
* false if this is being managed elsewhere
* @return true if the exchange should have listeners configured for it by the destination, false if this is being managed elsewhere
* @see #setConfigureListeners(boolean)
*/
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)
{
@ -981,7 +1059,7 @@ public class HttpExchange
HttpClient httpClient = destination.getHttpClient();
long timeout = getTimeout();
if (timeout > 0)
httpClient.schedule(_timeoutTask, timeout);
httpClient.schedule(_timeoutTask,timeout);
else
httpClient.schedule(_timeoutTask);
}
@ -1045,7 +1123,7 @@ public class HttpExchange
}
finally
{
synchronized(HttpExchange.this)
synchronized (HttpExchange.this)
{
_onRequestCompleteDone = true;
// Member _onDone may already be true, for example
@ -1066,7 +1144,7 @@ public class HttpExchange
}
finally
{
synchronized(HttpExchange.this)
synchronized (HttpExchange.this)
{
_onResponseCompleteDone = true;
// Member _onDone may already be true, for example
@ -1101,7 +1179,7 @@ public class HttpExchange
public void onRetry()
{
HttpExchange.this.setRetryStatus( true );
HttpExchange.this.setRetryStatus(true);
try
{
HttpExchange.this.onRetry();

View File

@ -110,25 +110,49 @@ public class RedirectListener extends HttpEventListenerWrapper
if (_location != null)
{
if (_location.indexOf("://")>0)
{
_exchange.setURL(_location);
}
else
{
_exchange.setRequestURI(_location);
}
// 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)
{
_destination.resend(_exchange);
}
else
{
// unwrap to find ultimate listener.
HttpEventListener listener=this;
while(listener instanceof HttpEventListenerWrapper)
{
listener=((HttpEventListenerWrapper)listener).getEventListener();
}
//reset the listener
_exchange.getEventListener().onRetry();
_exchange.reset();
_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);
}
@ -156,5 +180,28 @@ public class RedirectListener extends HttpEventListenerWrapper
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.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.UnresolvedAddressException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
@ -48,7 +51,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
private final HttpClient _httpClient;
private final Manager _selectorManager=new Manager();
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
private SSLContext _sslContext;
private Buffers _sslBuffers;
/**
@ -89,31 +91,34 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
public void startConnection( HttpDestination destination )
throws IOException
{
SocketChannel channel = null;
try
{
SocketChannel channel = SocketChannel.open();
channel = SocketChannel.open();
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
channel.socket().setTcpNoDelay(true);
if (_httpClient.isConnectBlocking())
{
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
channel.configureBlocking(false);
_selectorManager.register( channel, destination );
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
channel.configureBlocking(false);
_selectorManager.register( channel, destination );
}
else
{
channel.configureBlocking( false );
channel.connect(address.toSocketAddress());
_selectorManager.register( channel, destination );
ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
channel.configureBlocking(false);
channel.connect(address.toSocketAddress());
_selectorManager.register(channel,destination);
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
_connectingChannels.put(channel, connectTimeout);
_connectingChannels.put(channel,connectTimeout);
}
}
catch(IOException ex)
{
if (channel != null)
channel.close();
destination.onConnectionFailed(ex);
}
}
@ -194,19 +199,16 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
{
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
if (_sslContext == null)
_sslContext = sslContextFactory.getSslContext();
SSLEngine sslEngine;
if (channel != null && sslContextFactory.isSessionCachingEnabled())
if (channel != null)
{
String peerHost = channel.socket().getInetAddress().getHostAddress();
int peerPort = channel.socket().getPort();
sslEngine = _sslContext.createSSLEngine(peerHost, peerPort);
sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
}
else
{
sslEngine = _sslContext.createSSLEngine();
sslEngine = sslContextFactory.newSslEngine();
}
sslEngine.setUseClientMode(true);
sslEngine.beginHandshake();

View File

@ -45,18 +45,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
public void startConnection(final HttpDestination destination) throws IOException
{
Socket socket=null;
if ( destination.isSecure() )
{
SSLContext sslContext = _httpClient.getSSLContext();
socket = sslContext.getSocketFactory().createSocket();
}
else
{
LOG.debug("Using Regular Socket");
socket = SocketFactory.getDefault().createSocket();
}
Socket socket= destination.isSecure()
?_httpClient.getSslContextFactory().newSslSocket()
:SocketFactory.getDefault().createSocket();
socket.setSoTimeout(0);
socket.setTcpNoDelay(true);
@ -97,6 +88,17 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
destination.onException(e);
}
}
finally
{
try
{
destination.returnConnection(connection,true);
}
catch (IOException e)
{
LOG.debug(e);
}
}
}
});

View File

@ -14,9 +14,9 @@
package org.eclipse.jetty.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
@ -25,6 +25,9 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @version $Revision$ $Date$
*/
@ -37,7 +40,7 @@ public abstract class AbstractConnectionTest
// httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
return httpClient;
}
@Test
public void testServerClosedConnection() throws Exception
{
@ -57,6 +60,19 @@ public abstract class AbstractConnectionTest
httpClient.send(exchange);
Socket remote = serverSocket.accept();
// HttpClient.send() above is async, so if we write the response immediately
// there is a chance that it arrives before the request is being sent, so we
// read the request before sending the response to avoid the race
InputStream input = remote.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line;
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
break;
}
OutputStream output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
@ -80,6 +96,15 @@ public abstract class AbstractConnectionTest
httpClient.send(exchange);
remote = serverSocket.accept();
input = remote.getInputStream();
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
break;
}
output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
@ -94,6 +119,105 @@ public abstract class AbstractConnectionTest
}
}
@Test
public void testServerClosedIncomplete() throws Exception
{
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(null);
int port=serverSocket.getLocalPort();
HttpClient httpClient = newHttpClient();
httpClient.setMaxConnectionsPerAddress(1);
httpClient.start();
try
{
CountDownLatch latch = new CountDownLatch(1);
HttpExchange exchange = new ConnectionExchange(latch);
exchange.setAddress(new Address("localhost", port));
exchange.setRequestURI("/");
httpClient.send(exchange);
Socket remote = serverSocket.accept();
// HttpClient.send() above is async, so if we write the response immediately
// there is a chance that it arrives before the request is being sent, so we
// read the request before sending the response to avoid the race
InputStream input = remote.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line;
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
break;
}
OutputStream output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
output.write("\r\n".getBytes("UTF-8"));
output.flush();
remote.close();
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
}
finally
{
httpClient.stop();
}
}
@Test
public void testServerHalfClosedIncomplete() throws Exception
{
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(null);
int port=serverSocket.getLocalPort();
HttpClient httpClient = newHttpClient();
httpClient.setIdleTimeout(10000);
httpClient.setMaxConnectionsPerAddress(1);
httpClient.start();
try
{
CountDownLatch latch = new CountDownLatch(1);
HttpExchange exchange = new ConnectionExchange(latch);
exchange.setAddress(new Address("localhost", port));
exchange.setRequestURI("/");
httpClient.send(exchange);
Socket remote = serverSocket.accept();
// HttpClient.send() above is async, so if we write the response immediately
// there is a chance that it arrives before the request is being sent, so we
// read the request before sending the response to avoid the race
InputStream input = remote.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line;
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
break;
}
OutputStream output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
output.write("\r\n".getBytes("UTF-8"));
output.flush();
remote.shutdownOutput();
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
}
finally
{
httpClient.stop();
}
}
@Test
public void testConnectionFailed() throws Exception
{
@ -262,16 +386,16 @@ public abstract class AbstractConnectionTest
}
}
private class ConnectionExchange extends HttpExchange
protected class ConnectionExchange extends HttpExchange
{
private final CountDownLatch latch;
private ConnectionExchange()
protected ConnectionExchange()
{
this.latch = null;
}
private ConnectionExchange(CountDownLatch latch)
protected ConnectionExchange(CountDownLatch latch)
{
this.latch = latch;
}

View File

@ -14,9 +14,7 @@
package org.eclipse.jetty.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.IOException;
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.nio.SelectChannelConnector;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.junit.After;
import org.junit.Before;
@ -45,8 +42,6 @@ import org.junit.Test;
*/
public abstract class AbstractHttpExchangeCancelTest
{
private static final Logger LOG = Log.getLogger(AbstractHttpExchangeCancelTest.class);
private Server server;
private Connector connector;

View File

@ -22,4 +22,12 @@ public class AsyncSelectConnectionTest extends AbstractConnectionTest
httpClient.setConnectBlocking(false);
return httpClient;
}
@Override
public void testServerHalfClosedIncomplete() throws Exception
{
super.testServerHalfClosedIncomplete();
}
}

View File

@ -13,19 +13,23 @@
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
{
@Override
public void setUp() throws Exception
private static ServerAndClientCreator serverAndClientCreator = new AsyncSslServerAndClientCreator();
@Before
public void setUpOnce() throws Exception
{
_scheme="https";
startServer();
_httpClient=new HttpClient();
_httpClient.setIdleTimeout(2000);
_httpClient.setTimeout(2500);
_httpClient.setConnectTimeout(1000);
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
_httpClient.setMaxConnectionsPerAddress(2);
_httpClient.start();
_server = serverAndClientCreator.createServer();
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
_port = _server.getConnectors()[0].getLocalPort();
}
}

View File

@ -13,28 +13,23 @@
package org.eclipse.jetty.client;
import java.io.FileInputStream;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
{
@Override
public void setUp() throws Exception
private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
@Before
public void setUpOnce() throws Exception
{
_scheme = "https";
startServer();
_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();
_scheme="https";
_server = serverAndClientCreator.createServer();
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
_port = _server.getConnectors()[0].getLocalPort();
}
@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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.junit.Assert.*;
import static org.junit.matchers.JUnitMatchers.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -30,13 +25,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.helperClasses.HttpServerAndClientCreator;
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
import org.eclipse.jetty.client.security.ProxyAuthorization;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus;
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.EofException;
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.handler.AbstractHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.toolchain.test.Stress;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/* ------------------------------------------------------------ */
@ -63,37 +51,44 @@ import org.junit.Test;
*/
public class HttpExchangeTest
{
private static final Logger LOG = Log.getLogger(HttpExchangeTest.class);
protected int _maxConnectionsPerAddress = 2;
protected String _scheme = "http";
protected Server _server;
protected int _port;
protected HttpClient _httpClient;
protected Connector _connector;
protected AtomicInteger _count = new AtomicInteger();
final static boolean verbose=false;
protected static int _maxConnectionsPerAddress = 2;
protected static String _scheme = "http";
protected static Server _server;
protected static int _port;
protected static HttpClient _httpClient;
protected static AtomicInteger _count = new AtomicInteger();
protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
protected static URI getBaseURI()
{
return URI.create(_scheme + "://localhost:" + _port + "/");
}
/* ------------------------------------------------------------ */
// TODO work out why BeforeClass does not work here?
@Before
public void setUp() throws Exception
public void setUpOnce() throws Exception
{
startServer();
_httpClient=new HttpClient();
_httpClient.setIdleTimeout(3000);
_httpClient.setTimeout(3500);
_httpClient.setConnectTimeout(2000);
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
_httpClient.start();
_scheme = "http";
_server = serverAndClientCreator.createServer();
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
_port = _server.getConnectors()[0].getLocalPort();
}
/* ------------------------------------------------------------ */
@After
public void tearDown() throws Exception
public void tearDownOnce() throws Exception
{
_httpClient.stop();
Thread.sleep(500);
stopServer();
long startTime = System.currentTimeMillis();
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,true);
sender(10,false);
sender(10,true);
if (Stress.isEnabled())
{
sender(100,false);
@ -118,67 +115,72 @@ public class HttpExchangeTest
sender(10000,false);
sender(10000,true);
}
else
{
sender(10,false);
sender(10,true);
}
}
/* ------------------------------------------------------------ */
/**
* Test sending data through the exchange.
*
*
* @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);
final CountDownLatch complete=new CountDownLatch(nb);
final CountDownLatch latch=new CountDownLatch(nb);
final CountDownLatch complete = new CountDownLatch(nb);
final AtomicInteger allcontent = new AtomicInteger(nb);
HttpExchange[] httpExchange = new HttpExchange[nb];
long start=System.currentTimeMillis();
for (int i=0; i<nb; i++)
long start = System.currentTimeMillis();
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";
int len=0;
String result = "pending";
int len = 0;
/* ------------------------------------------------------------ */
@Override
protected void onRequestCommitted()
{
result="committed";
if (verbose)
System.err.println("[ ");
result = "committed";
}
/* ------------------------------------------------------------ */
@Override
protected void onRequestComplete() throws IOException
{
result="sent";
if (verbose)
System.err.println("[ ==");
result = "sent";
}
@Override
/* ------------------------------------------------------------ */
protected void onResponseStatus(Buffer version, int status, Buffer reason)
{
result="status";
if (verbose)
System.err.println("] "+version+" "+status+" "+reason);
result = "status";
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseHeader(Buffer name, Buffer value)
{
if (verbose)
System.err.println("] "+name+": "+value);
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseHeaderComplete() throws IOException
{
result="content";
if (verbose)
System.err.println("] -");
result = "content";
super.onResponseHeaderComplete();
}
@ -186,20 +188,22 @@ public class HttpExchangeTest
@Override
protected void onResponseContent(Buffer content)
{
len+=content.length();
len += content.length();
if (verbose)
System.err.println("] "+content.length()+" -> "+len);
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseComplete()
{
result="complete";
if (len==2009)
latch.countDown();
if (verbose)
System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
result = "complete";
if (len == 2009)
allcontent.decrementAndGet();
else
{
System.err.println(n+" ONLY "+len);
}
System.err.println(n + " ONLY " + len+ "/2009");
complete.countDown();
}
@ -207,9 +211,11 @@ public class HttpExchangeTest
@Override
protected void onConnectionFailed(Throwable ex)
{
if (verbose)
System.err.println("] "+ex);
complete.countDown();
result="failed";
System.err.println(n+" FAILED "+ex);
result = "failed";
System.err.println(n + " FAILED " + ex);
super.onConnectionFailed(ex);
}
@ -217,9 +223,11 @@ public class HttpExchangeTest
@Override
protected void onException(Throwable ex)
{
if (verbose)
System.err.println("] "+ex);
complete.countDown();
result="excepted";
System.err.println(n+" EXCEPTED "+ex);
result = "excepted";
System.err.println(n + " EXCEPTED " + ex);
super.onException(ex);
}
@ -227,9 +235,11 @@ public class HttpExchangeTest
@Override
protected void onExpire()
{
if (verbose)
System.err.println("] expired");
complete.countDown();
result="expired";
System.err.println(n+" EXPIRED "+len);
result = "expired";
System.err.println(n + " EXPIRED " + len);
super.onExpire();
}
@ -237,29 +247,24 @@ public class HttpExchangeTest
@Override
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");
if (close)
httpExchange[n].setRequestHeader("Connection","close");
_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(elapsed>0)
System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
*/
if (!complete.await(2,TimeUnit.SECONDS))
System.err.println(_httpClient.dump());
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++)
{
ContentExchange httpExchange=new ContentExchange();
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, null, null, null));
httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
_httpClient.send(httpExchange);
@ -288,12 +293,14 @@ public class HttpExchangeTest
for (int i=0;i<10;i++)
{
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);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result=httpExchange.getResponseContent();
assertNotNull("Should have received response content", result);
assertEquals("i="+i,0,result.indexOf("<hello>"));
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
assertEquals(HttpExchange.STATUS_COMPLETED, status);
@ -308,17 +315,16 @@ public class HttpExchangeTest
for (int i=0;i<10;i++)
{
ContentExchange httpExchange=new ContentExchange();
httpExchange.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
URI uri = getBaseURI().resolve("?i=" + i);
httpExchange.setURI(uri);
httpExchange.setMethod(HttpMethods.GET);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
assertNotNull(httpExchange.getLocalAddress());
//System.out.println("Local Address: " + httpExchange.getLocalAddress());
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result=httpExchange.getResponseContent();
assertNotNull("Should have received response content", result);
assertEquals("i="+i,0,result.indexOf("<hello>"));
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
assertEquals(HttpExchange.STATUS_COMPLETED, status);
@ -355,7 +361,7 @@ public class HttpExchangeTest
throwable.set(x);
}
};
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
httpExchange.setURI(getBaseURI());
httpExchange.setMethod("SLEEP");
_httpClient.send(httpExchange);
new Thread()
@ -374,6 +380,7 @@ public class HttpExchangeTest
System.err.println(throwable.get());
assertTrue(throwable.get().toString().indexOf("close")>=0);
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
_httpClient.start();
}
/* ------------------------------------------------------------ */
@ -381,7 +388,54 @@ public class HttpExchangeTest
public void testBigPostWithContentExchange() throws Exception
{
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 niobuf = new DirectNIOBuffer(size*36*1024);
@ -394,28 +448,27 @@ public class HttpExchangeTest
niobuf.put(bytes);
}
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(babuf);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
assertEquals(HttpExchange.STATUS_COMPLETED,status);
String result=httpExchange.getResponseContent();
assertEquals(babuf.length(),result.length());
httpExchange.reset();
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(niobuf);
_httpClient.send(httpExchange);
status = httpExchange.waitForDone();
assertEquals(HttpExchange.STATUS_COMPLETED, status);
result=httpExchange.getResponseContent();
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);
final String data="012345678901234567890123456789012345678901234567890123456789";
@ -447,7 +500,7 @@ public class HttpExchangeTest
@Override
public int read(byte[] b, int off, int len) throws IOException
{
if (_index>=data.length())
if (_index >= data.length())
return -1;
try
@ -458,28 +511,28 @@ public class HttpExchangeTest
{
e.printStackTrace();
}
int l=0;
while (l<5 && _index<data.length() && l<len)
b[off+l++]=(byte)data.charAt(_index++);
int l = 0;
while (l < 5 && _index < data.length() && l < len)
b[off + l++] = (byte)data.charAt(_index++);
return l;
}
};
httpExchange.setRequestContentSource(content);
//httpExchange.setRequestContent(new ByteArrayBuffer(data));
// httpExchange.setRequestContent(new ByteArrayBuffer(data));
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result=httpExchange.getResponseContent();
assertEquals(HttpExchange.STATUS_COMPLETED, status);
// httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result = httpExchange.getResponseContent();
assertEquals(HttpExchange.STATUS_COMPLETED,status);
assertEquals(data,result);
}
/* ------------------------------------------------------------ */
@Test
public void testProxy() throws Exception
@ -499,6 +552,7 @@ public class HttpExchangeTest
int status = httpExchange.waitForDone();
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result=httpExchange.getResponseContent();
assertNotNull("Should have received response content", result);
result=result.trim();
assertEquals(HttpExchange.STATUS_COMPLETED, status);
assertTrue(result.startsWith("Proxy request: http://jetty.eclipse.org:8080/jetty-6"));
@ -515,36 +569,42 @@ public class HttpExchangeTest
@Test
public void testReserveConnections () throws Exception
{
final HttpDestination destination = _httpClient.getDestination (new Address("localhost", _port), _scheme.equalsIgnoreCase("https"));
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
for (int i=0; i < _maxConnectionsPerAddress; i++)
{
connections[i] = destination.reserveConnection(200);
assertNotNull(connections[i]);
HttpExchange ex = new ContentExchange();
ex.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
ex.setMethod(HttpMethods.GET);
connections[i].send(ex);
}
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
final HttpDestination destination = _httpClient.getDestination(new Address("localhost",_port),_scheme.equalsIgnoreCase("https"));
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
for (int i = 0; i < _maxConnectionsPerAddress; i++)
{
connections[i] = destination.reserveConnection(200);
assertNotNull(connections[i]);
HttpExchange ex = new ContentExchange();
ex.setURI(getBaseURI().resolve("?i=" + i));
ex.setMethod(HttpMethods.GET);
connections[i].send(ex);
}
//try to get a connection, and only wait 500ms, as we have
//already reserved the max, should return null
Connection c = destination.reserveConnection(500);
assertNull(c);
// try to get a connection, and only wait 500ms, as we have
// already reserved the max, should return null
Connection c = destination.reserveConnection(500);
assertNull(c);
//unreserve first connection
destination.returnConnection(connections[0], false);
// unreserve first connection
destination.returnConnection(connections[0],false);
//reserving one should now work
c = destination.reserveConnection(500);
assertNotNull(c);
// reserving one should now work
c = destination.reserveConnection(500);
assertNotNull(c);
// release connections
for (HttpConnection httpConnection : connections){
destination.returnConnection(httpConnection,false);
}
}
@Test
public void testOptionsWithExchange() throws Exception
{
ContentExchange httpExchange = new ContentExchange(true);
httpExchange.setURL(_scheme+"://localhost:"+_port);
httpExchange.setURL(getBaseURI().toASCIIString());
httpExchange.setRequestURI("*");
httpExchange.setMethod(HttpMethods.OPTIONS);
// httpExchange.setRequestHeader("Connection","close");
@ -555,8 +615,10 @@ public class HttpExchangeTest
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
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 expectedMethods[] =
{ "GET", "HEAD", "POST", "PUT", "DELETE", "MOVE", "OPTIONS", "TRACE" };
@ -564,9 +626,6 @@ public class HttpExchangeTest
{
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
{
byte[] buffer=new byte[1024];
byte[] buffer = new byte[1024];
int len;
while ((len=in.read(buffer))>=0)
while ((len = in.read(buffer)) >= 0)
{
out.write(buffer,0,len);
}
}
catch (EofException e)
{
System.err.println("HttpExchangeTest#copyStream: "+e);
System.err.println("HttpExchangeTest#copyStream: " + e);
}
catch (IOException e)
{
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,6 +13,16 @@
package org.eclipse.jetty.client;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import static org.junit.Assert.assertEquals;
public class SocketConnectionTest extends AbstractConnectionTest
{
protected HttpClient newHttpClient()
@ -21,10 +31,61 @@ public class SocketConnectionTest extends AbstractConnectionTest
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
return httpClient;
}
@Override
public void testServerClosedConnection()
public void testServerClosedConnection() throws Exception
{
// TODO work out why this does not work
// Differently from the SelectConnector, the SocketConnector cannot detect server closes.
// Therefore, upon a second send, the exchange will fail.
// Applications needs to retry it explicitly.
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(null);
int port=serverSocket.getLocalPort();
HttpClient httpClient = this.newHttpClient();
httpClient.setMaxConnectionsPerAddress(1);
httpClient.start();
try
{
CountDownLatch latch = new CountDownLatch(1);
HttpExchange exchange = new ConnectionExchange(latch);
exchange.setAddress(new Address("localhost", port));
exchange.setRequestURI("/");
httpClient.send(exchange);
Socket remote = serverSocket.accept();
// HttpClient.send() above is async, so if we write the response immediately
// there is a chance that it arrives before the request is being sent, so we
// read the request before sending the response to avoid the race
InputStream input = remote.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String line;
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
break;
}
OutputStream output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
output.write("\r\n".getBytes("UTF-8"));
output.flush();
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
remote.close();
exchange.reset();
httpClient.send(exchange);
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
}
finally
{
httpClient.stop();
}
}
}

View File

@ -13,67 +13,36 @@
package org.eclipse.jetty.client;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.*;
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.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.Stress;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Functional testing for HttpExchange.
*
*
*
*/
public class SslHttpExchangeTest extends HttpExchangeTest
{
protected static ServerAndClientCreator serverAndClientCreator = new SslServerAndClientCreator();
/* ------------------------------------------------------------ */
@Before
@Override
public void setUp() throws Exception
public void setUpOnce() throws Exception
{
_scheme="https";
startServer();
_httpClient=new HttpClient();
_httpClient.setIdleTimeout(2000);
_httpClient.setTimeout(2500);
_httpClient.setConnectTimeout(1000);
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
_httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
_httpClient.setMaxConnectionsPerAddress(2);
_httpClient.start();
_server = serverAndClientCreator.createServer();
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
Connector[] connectors = _server.getConnectors();
_port = connectors[0].getLocalPort();
}
/* ------------------------------------------------------------ */
@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()
{

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>
<artifactId>maven-dependency-plugin</artifactId>
<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>
<id>copy</id>
<phase>generate-resources</phase>
@ -324,187 +173,6 @@
<outputDirectory>${assembly-directory}/</outputDirectory>
<destFileName>VERSION.txt</destFileName>
</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>
<groupId>org.eclipse.jetty</groupId>
<artifactId>test-jetty-webapp</artifactId>
@ -525,36 +193,77 @@
<outputDirectory>${assembly-directory}</outputDirectory>
<destFileName>start.jar</destFileName>
</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>
</configuration>
</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>
</plugin>
<plugin>
@ -663,12 +372,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-overlay-deployer</artifactId>
<artifactId>jetty-servlets</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-overlay-deployer</artifactId>
<artifactId>jetty-monitor</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@ -676,5 +385,17 @@
<artifactId>jetty-websocket</artifactId>
<version>${project.version}</version>
</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>
</project>

View File

@ -483,8 +483,13 @@ public abstract class AbstractGenerator implements Generator
{
if (close)
_persistent=false;
if (!isCommitted())
if (isCommitted())
{
LOG.debug("sendError on committed: {} {}",code,reason);
}
else
{
LOG.debug("sendError: {} {}",code,reason);
setResponse(code, reason);
if (content != null)
{

View File

@ -4,15 +4,16 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.http;
import java.io.EOFException;
import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
@ -67,7 +68,7 @@ public class HttpParser implements Parser
private String _multiLineValue;
private int _responseStatus; // If >0 then we are parsing a response
private boolean _forceContentBuffer;
/* ------------------------------------------------------------------------------- */
protected final View _contentView=new View(); // View of the content in the buffer for {@link Input}
protected int _state=STATE_START;
@ -78,7 +79,7 @@ public class HttpParser implements Parser
protected int _chunkLength;
protected int _chunkPosition;
private boolean _headResponse;
/* ------------------------------------------------------------------------------- */
/**
* Constructor.
@ -103,7 +104,7 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
/**
* Constructor.
* @param buffers the buffers to use
* @param buffers the buffers to use
* @param endp the endpoint
* @param handler the even handler
*/
@ -134,7 +135,7 @@ public class HttpParser implements Parser
{
_headResponse=head;
}
/* ------------------------------------------------------------------------------- */
public int getState()
{
@ -170,7 +171,7 @@ public class HttpParser implements Parser
{
return isState(STATE_END);
}
/* ------------------------------------------------------------ */
public boolean isMoreInBuffer()
throws IOException
@ -203,11 +204,11 @@ public class HttpParser implements Parser
if (parseNext()<0)
return;
}
/* ------------------------------------------------------------------------------- */
/**
* Parse until END state.
* This method will parse any remaining content in the current buffer. It does not care about the
* This method will parse any remaining content in the current buffer. It does not care about the
* {@link #getState current state} of the parser.
* @see #parse
* @see #parseNext
@ -216,7 +217,7 @@ public class HttpParser implements Parser
{
int progress = parseNext();
int total=progress>0?1:0;
// continue parsing
while (!isComplete() && _buffer!=null && _buffer.length()>0)
{
@ -237,9 +238,9 @@ public class HttpParser implements Parser
{
int progress=0;
if (_state == STATE_END)
if (_state == STATE_END)
return 0;
if (_buffer==null)
{
if (_header == null)
@ -252,23 +253,33 @@ public class HttpParser implements Parser
_tok0.setPutIndex(_tok0.getIndex());
_tok1.setPutIndex(_tok1.getIndex());
}
if (_state == STATE_CONTENT && _contentPosition == _contentLength)
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
return 1;
}
int length=_buffer.length();
// Fill buffer if we can
if (length == 0)
{
long filled=fill();
if (filled < 0)
long filled=-1;
IOException ex=null;
try
{
filled=fill();
}
catch(IOException e)
{
LOG.debug(this.toString(),e);
ex=e;
}
if (filled < 0 || _endp.isInputShutdown())
{
if (_headResponse && _state>STATE_END)
{
@ -284,19 +295,25 @@ public class HttpParser implements Parser
Buffer chunk=_buffer.get(_buffer.length());
_contentPosition += chunk.length();
_contentView.update(chunk);
_handler.content(chunk); // May recurse here
_handler.content(chunk); // May recurse here
}
_state=STATE_END;
_handler.messageComplete(_contentPosition);
return 1;
}
if (ex!=null)
throw ex;
if (!isComplete() && !isIdle())
throw new EOFException();
return -1;
}
length=_buffer.length();
}
// EventHandler header
byte ch;
byte[] array=_buffer.array();
@ -308,16 +325,16 @@ public class HttpParser implements Parser
progress++;
last=_state;
}
ch=_buffer.get();
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
{
_eol=HttpTokens.LINE_FEED;
continue;
}
_eol=0;
switch (_state)
{
case STATE_START:
@ -464,22 +481,22 @@ public class HttpParser implements Parser
_state=STATE_HEADER_VALUE;
break;
}
default:
{
// handler last header if any
if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
{
Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
_cached=null;
Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
int ho=HttpHeaders.CACHE.getOrdinal(header);
if (ho >= 0)
{
int vo;
int vo;
switch (ho)
{
case HttpHeaders.CONTENT_LENGTH_ORDINAL:
@ -498,7 +515,7 @@ public class HttpParser implements Parser
_contentLength=HttpTokens.NO_CONTENT;
}
break;
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
value=HttpHeaderValues.CACHE.lookup(value);
vo=HttpHeaderValues.CACHE.getOrdinal(value);
@ -509,22 +526,22 @@ public class HttpParser implements Parser
String c=value.toString(StringUtil.__ISO_8859_1);
if (c.endsWith(HttpHeaderValues.CHUNKED))
_contentLength=HttpTokens.CHUNKED_CONTENT;
else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
throw new HttpException(400,null);
}
break;
}
}
_handler.parsedHeader(header, value);
_tok0.setPutIndex(_tok0.getIndex());
_tok1.setPutIndex(_tok1.getIndex());
_multiLineValue=null;
}
_buffer.setMarkIndex(-1);
// now handle ch
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
@ -544,7 +561,7 @@ public class HttpParser implements Parser
_eol=ch;
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
_eol=_buffer.get();
// We convert _contentLength to an int for this switch statement because
// we don't care about the amount of data available just whether there is some.
switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
@ -553,19 +570,19 @@ public class HttpParser implements Parser
_state=STATE_EOF_CONTENT;
_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.CHUNKED_CONTENT:
_state=STATE_CHUNKED_CONTENT;
_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.NO_CONTENT:
_state=STATE_END;
returnBuffers();
_handler.headerComplete();
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
break;
default:
_state=STATE_CONTENT;
_handler.headerComplete(); // May recurse here !
@ -579,7 +596,7 @@ public class HttpParser implements Parser
_length=1;
_buffer.mark();
_state=STATE_HEADER_NAME;
// try cached name!
if (array!=null)
{
@ -592,10 +609,10 @@ public class HttpParser implements Parser
length=_buffer.length();
}
}
}
}
}
}
break;
case STATE_HEADER_NAME:
@ -617,16 +634,16 @@ public class HttpParser implements Parser
case HttpTokens.SPACE:
case HttpTokens.TAB:
break;
default:
default:
{
_cached=null;
if (_length == -1)
if (_length == -1)
_buffer.mark();
_length=_buffer.getIndex() - _buffer.markIndex();
_state=STATE_HEADER_IN_NAME;
_state=STATE_HEADER_IN_NAME;
}
}
break;
case STATE_HEADER_IN_NAME:
@ -682,11 +699,11 @@ public class HttpParser implements Parser
break;
default:
{
if (_length == -1)
if (_length == -1)
_buffer.mark();
_length=_buffer.getIndex() - _buffer.markIndex();
_state=STATE_HEADER_IN_VALUE;
}
}
}
break;
@ -720,9 +737,9 @@ public class HttpParser implements Parser
break;
}
} // end of HEADER states loop
// ==========================
// Handle HEAD response
if (_responseStatus>0 && _headResponse)
{
@ -731,10 +748,10 @@ public class HttpParser implements Parser
}
// ==========================
// Handle _content
length=_buffer.length();
Buffer chunk;
Buffer chunk;
last=_state;
while (_state > STATE_END && length > 0)
{
@ -743,7 +760,7 @@ public class HttpParser implements Parser
progress++;
last=_state;
}
if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
{
_eol=_buffer.get();
@ -757,11 +774,11 @@ public class HttpParser implements Parser
chunk=_buffer.get(_buffer.length());
_contentPosition += chunk.length();
_contentView.update(chunk);
_handler.content(chunk); // May recurse here
_handler.content(chunk); // May recurse here
// TODO adjust the _buffer to keep unconsumed content
return 1;
case STATE_CONTENT:
case STATE_CONTENT:
{
long remaining=_contentLength - _contentPosition;
if (remaining == 0)
@ -770,24 +787,24 @@ public class HttpParser implements Parser
_handler.messageComplete(_contentPosition);
return 1;
}
if (length > remaining)
if (length > remaining)
{
// We can cast reamining to an int as we know that it is smaller than
// or equal to length which is already an int.
// or equal to length which is already an int.
length=(int)remaining;
}
chunk=_buffer.get(length);
_contentPosition += chunk.length();
_contentView.update(chunk);
_handler.content(chunk); // May recurse here
_handler.content(chunk); // May recurse here
if(_contentPosition == _contentLength)
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
}
}
// TODO adjust the _buffer to keep unconsumed content
return 1;
}
@ -814,7 +831,7 @@ public class HttpParser implements Parser
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
_eol=ch;
if (_chunkLength == 0)
{
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
@ -858,8 +875,8 @@ public class HttpParser implements Parser
}
break;
}
case STATE_CHUNK:
case STATE_CHUNK:
{
int remaining=_chunkLength - _chunkPosition;
if (remaining == 0)
@ -867,13 +884,13 @@ public class HttpParser implements Parser
_state=STATE_CHUNKED_CONTENT;
break;
}
else if (length > remaining)
else if (length > remaining)
length=remaining;
chunk=_buffer.get(length);
_contentPosition += chunk.length();
_chunkPosition += chunk.length();
_contentView.update(chunk);
_handler.content(chunk); // May recurse here
_handler.content(chunk); // May recurse here
// TODO adjust the _buffer to keep unconsumed content
return 1;
}
@ -881,13 +898,13 @@ public class HttpParser implements Parser
length=_buffer.length();
}
return progress;
}
/* ------------------------------------------------------------------------------- */
/** fill the buffers from the endpoint
*
*
*/
public long fill() throws IOException
{
@ -898,14 +915,14 @@ public class HttpParser implements Parser
_tok0=new View.CaseInsensitive(_buffer);
_tok1=new View.CaseInsensitive(_buffer);
}
// Is there unconsumed content in body buffer
if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
{
_buffer=_body;
return _buffer.length();
}
// Shall we switch to a body buffer?
if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
{
@ -913,20 +930,20 @@ public class HttpParser implements Parser
_body=_buffers.getBuffer();
_buffer=_body;
}
// Do we have somewhere to fill from?
if (_endp != null )
{
// Shall we compact the body?
if (_buffer==_body || _state>STATE_END)
if (_buffer==_body || _state>STATE_END)
{
_buffer.compact();
}
// Are we full?
if (_buffer.space() == 0)
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
if (_buffer.space() == 0)
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
try
{
return _endp.fill(_buffer);
@ -943,7 +960,7 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
/** Skip any CRLFs in buffers
*
*
*/
public void skipCRLF()
{
@ -971,12 +988,12 @@ public class HttpParser implements Parser
else
break;
}
}
/* ------------------------------------------------------------------------------- */
public void reset()
{
{
// reset state
_contentView.setGetIndex(_contentView.putIndex());
_state=STATE_START;
@ -1026,12 +1043,12 @@ public class HttpParser implements Parser
public void returnBuffers()
{
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
{
{
if (_buffer==_body)
_buffer=_header;
if (_buffers!=null)
_buffers.returnBuffer(_body);
_body=null;
_body=null;
}
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
@ -1042,7 +1059,7 @@ public class HttpParser implements Parser
_header=null;
}
}
/* ------------------------------------------------------------------------------- */
public void setState(int state)
{
@ -1055,13 +1072,13 @@ public class HttpParser implements Parser
{
return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
}
/* ------------------------------------------------------------------------------- */
@Override
public String toString()
{
return "state=" + _state + " length=" + _length + " len=" + _contentLength;
}
}
/* ------------------------------------------------------------ */
public Buffer getHeaderBuffer()
@ -1072,7 +1089,7 @@ public class HttpParser implements Parser
}
return _header;
}
/* ------------------------------------------------------------ */
public Buffer getBodyBuffer()
{
@ -1086,20 +1103,20 @@ public class HttpParser implements Parser
public void setForceContentBuffer(boolean force)
{
_forceContentBuffer=force;
}
}
/* ------------------------------------------------------------ */
public Buffer blockForContent(long maxIdleTime) throws IOException
{
if (_contentView.length()>0)
return _contentView;
if (getState() <= HttpParser.STATE_END)
if (getState() <= HttpParser.STATE_END)
return null;
try
{
parseNext();
// parse until some progress is made (or IOException thrown for timeout)
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp!=null && _endp.isOpen())
{
@ -1123,9 +1140,9 @@ public class HttpParser implements Parser
_endp.close();
throw e;
}
return _contentView.length()>0?_contentView:null;
}
return _contentView.length()>0?_contentView:null;
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
@ -1143,11 +1160,11 @@ public class HttpParser implements Parser
return 0;
}
parseNext();
return _contentView==null?0:_contentView.length();
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@ -1175,7 +1192,7 @@ public class HttpParser implements Parser
*/
public abstract void startRequest(Buffer method, Buffer url, Buffer version)
throws IOException;
/**
* This is the method called by parser when the HTTP request line is parsed
*/
@ -1185,5 +1202,5 @@ public class HttpParser implements Parser
}

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.http;
@ -34,7 +34,7 @@ import org.eclipse.jetty.util.URIUtil;
* /foo/bar - an exact path specification.
* /foo/* - a prefix path specification (must end '/*').
* *.ext - a suffix path specification.
* / - the default path specification.
* / - the default path specification.
* </PRE>
* Matching is performed in the following order <NL>
* <LI>Exact match.
@ -43,24 +43,24 @@ import org.eclipse.jetty.util.URIUtil;
* <LI>default.
* </NL>
* Multiple path specifications can be mapped by providing a list of
* specifications. By default this class uses characters ":," as path
* separators, unless configured differently by calling the static
* method @see PathMap#setPathSpecSeparators(String)
* specifications. By default this class uses characters ":," as path
* separators, unless configured differently by calling the static
* method @see PathMap#setPathSpecSeparators(String)
* <P>
* 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.
* <P>
* This class is not synchronized. If concurrent modifications are
* possible then it should be synchronized at a higher level.
*
*
*
*/
public class PathMap extends HashMap implements Externalizable
{
/* ------------------------------------------------------------ */
private static String __pathSpecSeparators = ":,";
/* ------------------------------------------------------------ */
/** Set the path spec separator.
* Multiple path specification may be included in a single string
@ -72,7 +72,7 @@ public class PathMap extends HashMap implements Externalizable
{
__pathSpecSeparators=s;
}
/* --------------------------------------------------------------- */
final StringMap _prefixMap=new StringMap();
final StringMap _suffixMap=new StringMap();
@ -83,7 +83,7 @@ public class PathMap extends HashMap implements Externalizable
Entry _default=null;
final Set _entrySet;
boolean _nodefault=false;
/* --------------------------------------------------------------- */
/** Construct empty PathMap.
*/
@ -102,7 +102,7 @@ public class PathMap extends HashMap implements Externalizable
_entrySet=entrySet();
_nodefault=nodefault;
}
/* --------------------------------------------------------------- */
/** Construct empty PathMap.
*/
@ -111,7 +111,7 @@ public class PathMap extends HashMap implements Externalizable
super (capacity);
_entrySet=entrySet();
}
/* --------------------------------------------------------------- */
/** Construct from dictionary PathMap.
*/
@ -120,7 +120,7 @@ public class PathMap extends HashMap implements Externalizable
putAll(m);
_entrySet=entrySet();
}
/* ------------------------------------------------------------ */
public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException
@ -128,7 +128,7 @@ public class PathMap extends HashMap implements Externalizable
HashMap map = new HashMap(this);
out.writeObject(map);
}
/* ------------------------------------------------------------ */
public void readExternal(java.io.ObjectInput in)
throws java.io.IOException, ClassNotFoundException
@ -136,7 +136,7 @@ public class PathMap extends HashMap implements Externalizable
HashMap map = (HashMap)in.readObject();
this.putAll(map);
}
/* --------------------------------------------------------------- */
/** Add a single path match to the PathMap.
* @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);
Object old =null;
while (tok.hasMoreTokens())
{
String spec=tok.nextToken();
if (!spec.startsWith("/") && !spec.startsWith("*."))
throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'");
old = super.put(spec,object);
// Make entry that was just created.
Entry entry = new Entry(spec,object);
@ -176,7 +176,7 @@ public class PathMap extends HashMap implements Externalizable
else if (spec.startsWith("*."))
_suffixMap.put(spec.substring(2),entry);
else if (spec.equals(URIUtil.SLASH))
{
{
if (_nodefault)
_exactMap.put(spec,entry);
else
@ -193,7 +193,7 @@ public class PathMap extends HashMap implements Externalizable
}
}
}
return old;
}
@ -209,8 +209,8 @@ public class PathMap extends HashMap implements Externalizable
return entry.getValue();
return null;
}
/* --------------------------------------------------------------- */
/** Get the entry mapped by the best specification.
* @param path the path.
@ -222,14 +222,14 @@ public class PathMap extends HashMap implements Externalizable
if (path==null)
return null;
int l=path.length();
int l=path.length();
// try exact match
entry=_exactMap.getEntry(path,0,l);
if (entry!=null)
return (Entry) entry.getValue();
// prefix search
int i=l;
while((i=path.lastIndexOf('/',i-1))>=0)
@ -238,11 +238,11 @@ public class PathMap extends HashMap implements Externalizable
if (entry!=null)
return (Entry) entry.getValue();
}
// Prefix Default
if (_prefixDefault!=null)
return _prefixDefault;
// Extension search
i=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);
if (entry!=null)
return (Entry) entry.getValue();
}
}
// Default
return _default;
}
/* --------------------------------------------------------------- */
/** Get all entries matched by the path.
* Best match first.
@ -263,20 +263,20 @@ public class PathMap extends HashMap implements Externalizable
* @return LazyList of Map.Entry instances key=pathSpec
*/
public Object getLazyMatches(String path)
{
{
Map.Entry entry;
Object entries=null;
if (path==null)
return LazyList.getList(entries);
int l=path.length();
// try exact match
entry=_exactMap.getEntry(path,0,l);
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
// prefix search
int i=l-1;
while((i=path.lastIndexOf('/',i-1))>=0)
@ -285,11 +285,11 @@ public class PathMap extends HashMap implements Externalizable
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
}
// Prefix Default
if (_prefixDefault!=null)
entries=LazyList.add(entries,_prefixDefault);
// Extension search
i=0;
while ((i=path.indexOf('.',i+1))>0)
@ -305,13 +305,13 @@ public class PathMap extends HashMap implements Externalizable
// Optimization for just the default
if (entries==null)
return _defaultSingletonList;
entries=LazyList.add(entries,_default);
}
return entries;
}
/* --------------------------------------------------------------- */
/** Get all entries matched by the path.
* Best match first.
@ -319,7 +319,7 @@ public class PathMap extends HashMap implements Externalizable
* @return List of Map.Entry instances key=pathSpec
*/
public List getMatches(String 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
*/
public boolean containsMatch(String path)
{
{
Entry match = getMatch(path);
return match!=null && !match.equals(_default);
}
/* --------------------------------------------------------------- */
/* --------------------------------------------------------------- */
@Override
public Object remove(Object pathSpec)
{
@ -362,7 +362,7 @@ public class PathMap extends HashMap implements Externalizable
}
return super.remove(pathSpec);
}
/* --------------------------------------------------------------- */
@Override
public void clear()
@ -374,7 +374,7 @@ public class PathMap extends HashMap implements Externalizable
_defaultSingletonList=null;
super.clear();
}
/* --------------------------------------------------------------- */
/**
* @return true if match.
@ -397,7 +397,7 @@ public class PathMap extends HashMap implements Externalizable
{
if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path))
return true;
if(isPathWildcardMatch(pathSpec, path))
return true;
}
@ -419,24 +419,24 @@ public class PathMap extends HashMap implements Externalizable
}
return false;
}
/* --------------------------------------------------------------- */
/** Return the portion of a path that matches a path spec.
* @return null if no match at all.
*/
public static String pathMatch(String pathSpec, String path)
{
{
char c = pathSpec.charAt(0);
if (c=='/')
{
if (pathSpec.length()==1)
return path;
if (pathSpec.equals(path))
return path;
if (isPathWildcardMatch(pathSpec, path))
return path.substring(0,pathSpec.length()-2);
}
@ -448,7 +448,7 @@ public class PathMap extends HashMap implements Externalizable
}
return null;
}
/* --------------------------------------------------------------- */
/** Return the portion of a path that is after a path spec.
* @return The path info string
@ -456,12 +456,12 @@ public class PathMap extends HashMap implements Externalizable
public static String pathInfo(String pathSpec, String path)
{
char c = pathSpec.charAt(0);
if (c=='/')
{
if (pathSpec.length()==1)
return null;
boolean wildcard = isPathWildcardMatch(pathSpec, path);
// 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 path.substring(pathSpec.length()-2);
}
}
}
return null;
}
@ -484,7 +484,7 @@ public class PathMap extends HashMap implements Externalizable
* @param base The base the path is relative to.
* @param pathSpec The spec of the path segment to ignore.
* @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,
String pathSpec,
@ -508,7 +508,7 @@ public class PathMap extends HashMap implements Externalizable
path = base + URIUtil.SLASH + info;
return path;
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@ -516,7 +516,7 @@ public class PathMap extends HashMap implements Externalizable
{
private final Object key;
private final Object value;
private String mapped;
private String mapped;
private transient String string;
Entry(Object key, Object value)
@ -529,7 +529,7 @@ public class PathMap extends HashMap implements Externalizable
{
return key;
}
public Object getValue()
{
return value;

View File

@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.security.InvalidParameterException;
import java.security.KeyStore;
import java.security.SecureRandom;
@ -42,7 +43,10 @@ import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
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.TrustManagerFactory;
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.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.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.CertificateUtils;
import org.eclipse.jetty.util.security.CertificateValidator;
@ -65,6 +71,8 @@ import org.eclipse.jetty.util.security.CertificateValidator;
*/
public class SslContextFactory extends AbstractLifeCycle
{
private static final Logger LOG = Log.getLogger(SslContextFactory.class);
public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
(Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
"SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
@ -82,8 +90,14 @@ public class SslContextFactory extends AbstractLifeCycle
/** String name of keystore password property. */
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. */
private Set<String> _excludeCipherSuites = null;
private final Set<String> _excludeCipherSuites = new HashSet<String>();
/** Included cipher suites. */
private Set<String> _includeCipherSuites = null;
@ -196,6 +210,7 @@ public class SslContextFactory extends AbstractLifeCycle
if (_keyStoreInputStream == null && _keyStorePath == null &&
_trustStoreInputStream == null && _trustStorePath == null )
{
LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
// Create a trust manager that does not validate certificate chains
TrustManager trustAllCerts = new X509TrustManager()
{
@ -218,11 +233,115 @@ public class SslContextFactory extends AbstractLifeCycle
}
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
@ -239,11 +358,21 @@ public class SslContextFactory extends AbstractLifeCycle
* The array of cipher suite names to exclude from
* {@link SSLEngine#setEnabledCipherSuites(String[])}
*/
public void setExcludeCipherSuites(String[] cipherSuites)
public void setExcludeCipherSuites(String... cipherSuites)
{
checkStarted();
_excludeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
checkNotStarted();
_excludeCipherSuites.clear();
_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
* {@link SSLEngine#setEnabledCipherSuites(String[])}
*/
public void setIncludeCipherSuites(String[] cipherSuites)
public void setIncludeCipherSuites(String... cipherSuites)
{
checkStarted();
checkNotStarted();
_includeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
}
@ -285,7 +414,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStore(String keyStorePath)
{
checkStarted();
checkNotStarted();
_keyStorePath = keyStorePath;
}
@ -306,7 +435,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreProvider(String keyStoreProvider)
{
checkStarted();
checkNotStarted();
_keyStoreProvider = keyStoreProvider;
}
@ -327,7 +456,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreType(String keyStoreType)
{
checkStarted();
checkNotStarted();
_keyStoreType = keyStoreType;
}
@ -341,7 +470,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public InputStream getKeyStoreInputStream()
{
checkConfig();
checkKeyStore();
return _keyStoreInputStream;
}
@ -355,7 +484,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
{
checkStarted();
checkNotStarted();
_keyStoreInputStream = keyStoreInputStream;
}
@ -376,7 +505,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setCertAlias(String certAlias)
{
checkStarted();
checkNotStarted();
_certAlias = certAlias;
}
@ -397,7 +526,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(String trustStorePath)
{
checkStarted();
checkNotStarted();
_trustStorePath = trustStorePath;
}
@ -418,7 +547,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStoreProvider(String trustStoreProvider)
{
checkStarted();
checkNotStarted();
_trustStoreProvider = trustStoreProvider;
}
@ -439,7 +568,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStoreType(String trustStoreType)
{
checkStarted();
checkNotStarted();
_trustStoreType = trustStoreType;
}
@ -453,7 +582,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public InputStream getTrustStoreInputStream()
{
checkConfig();
checkKeyStore();
return _trustStoreInputStream;
}
@ -467,7 +596,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
{
checkStarted();
checkNotStarted();
_trustStoreInputStream = trustStoreInputStream;
}
@ -490,7 +619,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setNeedClientAuth(boolean needClientAuth)
{
checkStarted();
checkNotStarted();
_needClientAuth = needClientAuth;
}
@ -513,7 +642,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setWantClientAuth(boolean wantClientAuth)
{
checkStarted();
checkNotStarted();
_wantClientAuth = wantClientAuth;
}
@ -545,7 +674,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setValidateCerts(boolean validateCerts)
{
checkStarted();
checkNotStarted();
_validateCerts = validateCerts;
}
@ -566,7 +695,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setValidatePeerCerts(boolean validatePeerCerts)
{
checkStarted();
checkNotStarted();
_validatePeerCerts = validatePeerCerts;
}
@ -593,7 +722,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setAllowRenegotiate(boolean allowRenegotiate)
{
checkStarted();
checkNotStarted();
_allowRenegotiate = allowRenegotiate;
}
@ -605,7 +734,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStorePassword(String password)
{
checkStarted();
checkNotStarted();
_keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
}
@ -617,7 +746,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyManagerPassword(String password)
{
checkStarted();
checkNotStarted();
_keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
}
@ -629,7 +758,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStorePassword(String password)
{
checkStarted();
checkNotStarted();
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
}
@ -652,7 +781,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setProvider(String provider)
{
checkStarted();
checkNotStarted();
_sslProvider = provider;
}
@ -675,7 +804,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setProtocol(String protocol)
{
checkStarted();
checkNotStarted();
_sslProtocol = protocol;
}
@ -700,7 +829,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSecureRandomAlgorithm(String algorithm)
{
checkStarted();
checkNotStarted();
_secureRandomAlgorithm = algorithm;
}
@ -721,7 +850,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
{
checkStarted();
checkNotStarted();
_keyManagerFactoryAlgorithm = algorithm;
}
@ -742,7 +871,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustManagerFactoryAlgorithm(String algorithm)
{
checkStarted();
checkNotStarted();
_trustManagerFactoryAlgorithm = algorithm;
}
@ -763,7 +892,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setCrlPath(String crlPath)
{
checkStarted();
checkNotStarted();
_crlPath = crlPath;
}
@ -786,7 +915,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setMaxCertPathLength(int maxCertPathLength)
{
checkStarted();
checkNotStarted();
_maxCertPathLength = maxCertPathLength;
}
@ -797,6 +926,8 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public SSLContext getSslContext()
{
if (!isStarted())
throw new IllegalStateException(getState());
return _context;
}
@ -807,60 +938,11 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSslContext(SSLContext sslContext)
{
checkStarted();
checkNotStarted();
_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.
@ -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
* 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)
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
check = false;
}
else
{
// 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)
{
_trustStore = _keyStore;
_trustStorePath = _keyStorePath;
_trustStoreInputStream = _keyStoreInputStream;
_trustStoreType = _keyStoreType;
_trustStoreProvider = _keyStoreProvider;
_trustStorePassword = _keyStorePassword;
_trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
}
_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
@ -1057,11 +1133,9 @@ public class SslContextFactory extends AbstractLifeCycle
}
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
* @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;
if (enabledCipherSuites != null)
Set<String> selected_protocols = new HashSet<String>();
// 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
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);
}
if ((supportedCipherSuites != null && supportedCipherSuites.length > 0) &&
(_includeCipherSuites != null && _includeCipherSuites.size() > 0))
{
Set<String> supportedCSList = new HashSet<String>(Arrays.asList(supportedCipherSuites));
for (String cipherName : _includeCipherSuites)
{
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()]);
else
selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
// Remove any excluded ciphers
if (_excludeCipherSuites != null)
selected_ciphers.removeAll(_excludeCipherSuites);
return selected_ciphers.toArray(new String[selected_ciphers.size()]);
}
/* ------------------------------------------------------------ */
/**
* Check if the lifecycle has been started and throw runtime exception
*/
protected void checkStarted()
protected void checkNotStarted()
{
if (isStarted())
{
throw new IllegalStateException("Cannot modify configuration after SslContextFactory was started");
}
throw new IllegalStateException("Cannot modify configuration when "+getState());
}
/* ------------------------------------------------------------ */
@ -1141,7 +1226,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setEnableCRLDP(boolean enableCRLDP)
{
checkStarted();
checkNotStarted();
_enableCRLDP = enableCRLDP;
}
@ -1161,7 +1246,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setEnableOCSP(boolean enableOCSP)
{
checkStarted();
checkNotStarted();
_enableOCSP = enableOCSP;
}
@ -1181,7 +1266,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setOcspResponderURL(String ocspResponderURL)
{
checkStarted();
checkNotStarted();
_ocspResponderURL = ocspResponderURL;
}
@ -1192,7 +1277,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStore(KeyStore keyStore)
{
checkStarted();
checkNotStarted();
_keyStore = keyStore;
}
@ -1203,7 +1288,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(KeyStore trustStore)
{
checkStarted();
checkNotStarted();
_trustStore = trustStore;
}
@ -1214,7 +1299,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreResource(Resource resource)
{
checkStarted();
checkNotStarted();
try
{
@ -1233,7 +1318,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(Resource resource)
{
checkStarted();
checkNotStarted();
try
{
@ -1299,4 +1384,83 @@ public class SslContextFactory extends AbstractLifeCycle
{
_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

@ -47,6 +47,7 @@ public interface EndPoint
* The buffer may chose to do a compact before filling.
* @return an <code>int</code> value indicating the number of bytes
* filled or -1 if EOF is reached.
* @throws EofException If input is shutdown or the endpoint is closed.
*/
int fill(Buffer buffer) throws IOException;
@ -59,6 +60,7 @@ public interface EndPoint
*
* @param buffer The buffer to flush. This buffers getIndex is updated.
* @return the number of bytes written
* @throws EofException If the endpoint is closed or output is shutdown.
*/
int flush(Buffer buffer) throws IOException;
@ -157,7 +159,7 @@ public interface EndPoint
/* ------------------------------------------------------------ */
/** Flush any buffered output.
* May fail to write all data if endpoint is non-blocking
* @throws IOException
* @throws EofException If the endpoint is closed or output is shutdown.
*/
public void flush() throws IOException;

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.bio;
@ -17,6 +17,7 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
@ -34,13 +35,13 @@ public class SocketEndPoint extends StreamEndPoint
final Socket _socket;
final InetSocketAddress _local;
final InetSocketAddress _remote;
/* ------------------------------------------------------------ */
/**
*
*
*/
public SocketEndPoint(Socket socket)
throws IOException
throws IOException
{
super(socket.getInputStream(),socket.getOutputStream());
_socket=socket;
@ -48,13 +49,13 @@ public class SocketEndPoint extends StreamEndPoint
_remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
super.setMaxIdleTime(_socket.getSoTimeout());
}
/* ------------------------------------------------------------ */
/**
*
*
*/
protected SocketEndPoint(Socket socket, int maxIdleTime)
throws IOException
throws IOException
{
super(socket.getInputStream(),socket.getOutputStream());
_socket=socket;
@ -63,7 +64,7 @@ public class SocketEndPoint extends StreamEndPoint
_socket.setSoTimeout(maxIdleTime>0?maxIdleTime:0);
super.setMaxIdleTime(maxIdleTime);
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#isClosed()
@ -73,19 +74,19 @@ public class SocketEndPoint extends StreamEndPoint
{
return super.isOpen() && _socket!=null && !_socket.isClosed();
}
/* ------------------------------------------------------------ */
@Override
public boolean isInputShutdown()
{
return !super.isOpen() || _socket!=null && _socket.isInputShutdown();
return !isOpen() || super.isInputShutdown();
}
/* ------------------------------------------------------------ */
@Override
public boolean isOutputShutdown()
{
return !super.isOpen() || _socket!=null && _socket.isOutputShutdown();
return !isOpen() || super.isOutputShutdown();
}
/* ------------------------------------------------------------ */
@ -94,9 +95,13 @@ public class SocketEndPoint extends StreamEndPoint
*/
@Override
public void shutdownOutput() throws IOException
{
if (!_socket.isClosed() && !_socket.isOutputShutdown())
_socket.shutdownOutput();
{
if (!isOutputShutdown())
{
super.shutdownOutput();
if (!(_socket instanceof SSLSocket))
_socket.shutdownOutput();
}
}
@ -106,11 +111,15 @@ public class SocketEndPoint extends StreamEndPoint
*/
@Override
public void shutdownInput() throws IOException
{
if (!_socket.isClosed() && !_socket.isInputShutdown())
_socket.shutdownInput();
{
if (!isInputShutdown())
{
super.shutdownInput();
if (!(_socket instanceof SSLSocket))
_socket.shutdownInput();
}
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#close()
@ -122,10 +131,10 @@ public class SocketEndPoint extends StreamEndPoint
_in=null;
_out=null;
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getLocalAddr()
*/
@Override
@ -133,12 +142,12 @@ public class SocketEndPoint extends StreamEndPoint
{
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
return StringUtil.ALL_INTERFACES;
return _local.getAddress().getHostAddress();
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getLocalHost()
*/
@Override
@ -146,12 +155,12 @@ public class SocketEndPoint extends StreamEndPoint
{
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
return StringUtil.ALL_INTERFACES;
return _local.getAddress().getCanonicalHostName();
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getLocalPort()
*/
@Override
@ -163,7 +172,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getRemoteAddr()
*/
@Override
@ -176,7 +185,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getRemoteHost()
*/
@Override
@ -188,7 +197,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getRemotePort()
*/
@Override
@ -200,7 +209,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
/*
/*
* @see org.eclipse.io.EndPoint#getConnection()
*/
@Override
@ -237,5 +246,5 @@ public class SocketEndPoint extends StreamEndPoint
_socket.close();
}
}
}

View File

@ -22,17 +22,13 @@ import java.net.SocketTimeoutException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.EndPoint;
/**
*
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class StreamEndPoint implements EndPoint
{
InputStream _in;
OutputStream _out;
int _maxIdleTime;
boolean _ishut;
boolean _oshut;
/**
*
@ -75,23 +71,33 @@ public class StreamEndPoint implements EndPoint
}
public void shutdownOutput() throws IOException
{
{
if (_oshut)
return;
_oshut = true;
if (_out!=null)
_out.close();
}
public boolean isInputShutdown()
{
return !isOpen();
return _ishut;
}
public void shutdownInput() throws IOException
{
{
if (_ishut)
return;
_ishut = true;
if (_in!=null)
_in.close();
}
public boolean isOutputShutdown()
{
return !isOpen();
return _oshut;
}
/*
* @see org.eclipse.io.BufferIO#close()
*/
@ -107,35 +113,43 @@ public class StreamEndPoint implements EndPoint
protected void idleExpired() throws IOException
{
_in.close();
if (_in!=null)
_in.close();
}
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#fill(org.eclipse.io.Buffer)
*/
public int fill(Buffer buffer) throws IOException
{
// TODO handle null array()
if (_in==null)
return 0;
int space=buffer.space();
if (space<=0)
{
if (buffer.hasContent())
return 0;
throw new IOException("FULL");
}
int space=buffer.space();
if (space<=0)
{
if (buffer.hasContent())
return 0;
throw new IOException("FULL");
}
try
{
return buffer.readFrom(_in,space);
}
catch(SocketTimeoutException e)
{
idleExpired();
return -1;
}
try
{
int read=buffer.readFrom(_in, space);
if (read<0 && isOpen())
{
if (!isInputShutdown())
shutdownInput();
else if (isOutputShutdown())
close();
}
return read;
}
catch(SocketTimeoutException e)
{
idleExpired();
return -1;
}
}
/* (non-Javadoc)
@ -143,7 +157,6 @@ public class StreamEndPoint implements EndPoint
*/
public int flush(Buffer buffer) throws IOException
{
// TODO handle null array()
if (_out==null)
return -1;
int length=buffer.length();
@ -313,13 +326,13 @@ public class StreamEndPoint implements EndPoint
{
return false;
}
/* ------------------------------------------------------------ */
public int getMaxIdleTime()
{
return _maxIdleTime;
}
/* ------------------------------------------------------------ */
public void setMaxIdleTime(int timeMs) throws IOException
{

View File

@ -109,9 +109,12 @@ public class ChannelEndPoint implements EndPoint
if (_channel.isOpen() && _channel instanceof SocketChannel)
{
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)
{
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 ByteBuffer bbuf=nbuf.getByteBuffer();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
//noinspection SynchronizationOnLocalVariableOrMethodParameter
try
{
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)
{
LOG.debug(x);
try
{
close();
@ -196,7 +206,6 @@ public class ChannelEndPoint implements EndPoint
if (len>0)
throw x;
LOG.ignore(x);
len=-1;
}
}

View File

@ -34,27 +34,48 @@ import org.eclipse.jetty.util.log.Logger;
*/
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 _manager;
private SelectionKey _key;
private final Runnable _handler = new Runnable()
{
public void run() { handle(); }
};
/** The desired value for {@link SelectionKey#interestOps()} */
private int _interestOps;
/**
* The connection instance is the handler for any IO activity on the endpoint.
* There is a different type of connection for HTTP, AJP, WebSocket and
* ProxyConnect. The connection may change for an SCEP as it is upgraded
* from HTTP to proxy connect or websocket.
*/
private volatile Connection _connection;
/** true if a thread has been dispatched to handle this endpoint */
private boolean _dispatched = false;
/** true if a non IO dispatch (eg async resume) is outstanding */
private boolean _redispatched = false;
/** true if the last write operation succeed and wrote all offered bytes */
private volatile boolean _writable = true;
private SelectionKey _key;
private int _interestOps;
/** True if a thread has is blocked in {@link #blockReadable(long)} */
private boolean _readBlocked;
private boolean _writeBlocked;
private boolean _open;
private volatile long _idleTimestamp;
/** True if a thread has is blocked in {@link #blockWritable(long)} */
private boolean _writeBlocked;
/** true if {@link SelectSet#destroyEndPoint(SelectChannelEndPoint)} has not been called */
private boolean _open;
private volatile long _idleTimestamp;
/* ------------------------------------------------------------ */
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
throws IOException
@ -90,6 +111,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
scheduleIdle();
}
/* ------------------------------------------------------------ */
public SelectionKey getSelectionKey()
{
@ -205,7 +227,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
if(!dispatched)
{
_dispatched = false;
__log.warn("Dispatched Failed! "+this+" to "+_manager);
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
updateKey();
}
}
@ -250,7 +272,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
public void checkIdleTimestamp(long now)
{
long idleTimestamp=_idleTimestamp;
if (idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
if (!getChannel().isOpen() || idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
idleExpired();
}
@ -260,6 +282,15 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_connection.idleExpired();
}
/* ------------------------------------------------------------ */
/**
* @return True if the endpoint has produced/consumed bytes itself (non application data).
*/
public boolean isProgressing()
{
return false;
}
/* ------------------------------------------------------------ */
/*
*/
@ -340,7 +371,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
__log.warn(e);
LOG.warn(e);
}
finally
{
@ -385,7 +416,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
__log.warn(e);
LOG.warn(e);
}
finally
{
@ -398,7 +429,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Throwable e)
{
// TODO remove this if it finds nothing
__log.warn(e);
LOG.warn(e);
if (e instanceof RuntimeException)
throw (RuntimeException)e;
if (e instanceof Error)
@ -414,10 +445,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
return true;
}
/* ------------------------------------------------------------ */
/* short cut for busyselectChannelServerTest */
public void clearWritable()
{
_writable=false;
}
/* ------------------------------------------------------------ */
public void scheduleWrite()
{
if (_writable==true)
LOG.debug("Required scheduleWrite {}",this);
_writable=false;
updateKey();
}
@ -445,7 +486,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Exception e)
{
_key=null;
__log.ignore(e);
LOG.ignore(e);
}
}
@ -483,7 +524,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (Exception e)
{
__log.ignore(e);
LOG.ignore(e);
if (_key!=null && _key.isValid())
{
_key.cancel();
@ -520,9 +561,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
cancelIdle();
if (_open)
{
_open=false;
_selectSet.destroyEndPoint(this);
}
_open=false;
_key = null;
}
}
@ -545,7 +586,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
final Connection next = _connection.handle();
if (next!=_connection)
{
__log.debug("{} replaced {}",next,_connection);
LOG.debug("{} replaced {}",next,_connection);
_connection=next;
continue;
}
@ -554,26 +595,26 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (ClosedChannelException e)
{
__log.ignore(e);
LOG.ignore(e);
}
catch (EofException e)
{
__log.debug("EOF", e);
try{close();}
catch(IOException e2){__log.ignore(e2);}
LOG.debug("EOF", e);
try{getChannel().close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (IOException e)
{
__log.warn(e.toString());
__log.debug(e);
try{close();}
catch(IOException e2){__log.ignore(e2);}
LOG.warn(e.toString());
LOG.debug(e);
try{getChannel().close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (Throwable e)
{
__log.warn("handle failed", e);
try{close();}
catch(IOException e2){__log.ignore(e2);}
LOG.warn("handle failed", e);
try{getChannel().close();}
catch(IOException e2){LOG.ignore(e2);}
}
dispatched=!undispatch();
}
@ -585,7 +626,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
dispatched=!undispatch();
while (dispatched)
{
__log.warn("SCEP.run() finally DISPATCHED");
LOG.warn("SCEP.run() finally DISPATCHED");
dispatched=!undispatch();
}
}
@ -605,7 +646,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (IOException e)
{
__log.ignore(e);
LOG.ignore(e);
}
finally
{
@ -620,7 +661,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
synchronized(this)
{
return "SCEP@" + hashCode() + _channel+
"[d=" + _dispatched + ",io=" + _interestOps+
"[o="+isOpen()+" d=" + _dispatched + ",io=" + _interestOps+
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
}
}

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.nio;
@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
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
* NIO scheduling to scale to large numbers of connections.
* <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 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 __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_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 int _maxIdleTime;
private int _lowResourcesMaxIdleTime;
private long _lowResourcesConnections;
@ -72,7 +66,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
private volatile int _set;
private boolean _deferringInterestedOps0=true;
private int _selectorPriorityDelta=0;
/* ------------------------------------------------------------ */
/**
* @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;
}
/* ------------------------------------------------------------ */
/**
* @param selectSets number of select sets to create
*/
public void setSelectSets(int selectSets)
{
long lrc = _lowResourcesConnections * _selectSets;
long lrc = _lowResourcesConnections * _selectSets;
_selectSets=selectSets;
_lowResourcesConnections=lrc/_selectSets;
}
/* ------------------------------------------------------------ */
/**
* @return the max idle time
@ -102,7 +96,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
return _maxIdleTime;
}
/* ------------------------------------------------------------ */
/**
* @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
*/
public SelectSet getSelectSet(int i)
{
return _selectSet[i];
}
/* ------------------------------------------------------------ */
/** Register a 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.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
int s=_set++;
int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
@ -144,7 +138,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
}
/* ------------------------------------------------------------ */
/** Register a 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.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
int s=_set++;
int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
@ -165,14 +159,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
set.wakeup();
}
}
/* ------------------------------------------------------------ */
/** Register a {@link ServerSocketChannel}
* @param acceptChannel
*/
public void register(ServerSocketChannel acceptChannel)
{
int s=_set++;
int s=_set++;
s=s%_selectSets;
SelectSet set=_selectSet[s];
set.addChange(acceptChannel);
@ -196,8 +190,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_selectorPriorityDelta=delta;
}
/* ------------------------------------------------------------ */
/**
* @return the lowResourcesConnections
@ -237,7 +231,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
}
/* ------------------------------------------------------------------------------- */
public abstract boolean dispatch(Runnable task);
@ -254,7 +248,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
_selectSet[i]= new SelectSet(i);
super.doStart();
// start a thread to Select
for (int i=0;i<getSelectSets();i++)
{
@ -271,7 +265,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
if (sets==null)
return;
SelectSet set=sets[id];
Thread.currentThread().setName(name+" Selector"+id);
if (getSelectorPriorityDelta()!=0)
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.debug(ex);
}
/* ------------------------------------------------------------ */
public String dump()
{
@ -375,8 +369,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
out.append(String.valueOf(this)).append("\n");
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 Timeout _timeout;
private final ConcurrentLinkedQueue<Object> _changes = new ConcurrentLinkedQueue<Object>();
private volatile Selector _selector;
private volatile Thread _selecting;
private int _jvmBug;
private int _selects;
private long _monitorStart;
private int _busySelects;
private long _monitorNext;
private boolean _pausing;
private SelectionKey _busyKey;
private int _busyKeyCount;
private long _log;
private int _paused;
private int _jvmFix0;
private int _jvmFix1;
private int _jvmFix2;
private boolean _paused;
private volatile long _idleTick;
private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>();
/* ------------------------------------------------------------ */
SelectSet(int acceptorID) throws Exception
{
@ -416,11 +402,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
// create a selector;
_selector = Selector.open();
_monitorStart=System.currentTimeMillis();
_monitorNext=_monitorStart+__MONITOR_PERIOD;
_log=_monitorStart+60000;
_monitorNext=System.currentTimeMillis()+__MONITOR_PERIOD;
}
/* ------------------------------------------------------------ */
public void addChange(Object change)
{
@ -429,7 +413,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/* ------------------------------------------------------------ */
public void addChange(SelectableChannel channel, Object att)
{
{
if (att==null)
addChange(channel);
else if (att instanceof EndPoint)
@ -437,11 +421,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
else
addChange(new ChannelAndAttachment(channel,att));
}
/* ------------------------------------------------------------ */
/**
* Select and dispatch tasks found from changes and the selector.
*
*
* @throws IOException
*/
public void doSelect() throws IOException
@ -450,6 +434,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_selecting=Thread.currentThread();
final Selector selector=_selector;
// Stopped concurrently ?
if (selector == null)
return;
// Make any key changes required
Object change;
@ -458,7 +445,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
Channel ch=null;
SelectionKey key=null;
try
{
if (change instanceof EndPoint)
@ -475,7 +462,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
final SelectableChannel channel=asc._channel;
ch=channel;
final Object att = asc._attachment;
if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected())
{
key = channel.register(selector,SelectionKey.OP_READ,att);
@ -517,7 +504,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
if (e instanceof ThreadDeath)
throw (ThreadDeath)e;
if (isRunning())
LOG.warn(e);
else
@ -525,7 +512,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
try
{
ch.close();
if (ch!=null)
ch.close();
}
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.
int selected=selector.selectNow();
_selects++;
long now=System.currentTimeMillis();
// if no immediate things to do
if (selected==0 && selector.selectedKeys().isEmpty())
{
@ -562,7 +549,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
_timeout.setNow(now);
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)
wait = to_next_timeout;
@ -571,24 +558,48 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
long before=now;
selected=selector.select(wait);
_selects++;
now = System.currentTimeMillis();
_timeout.setNow(now);
if (__JVMBUG_THRESHHOLD>0)
checkJvmBugs(before, now, wait, selected);
// If we are monitoring for busy selector
// 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
if (_selector==null || !selector.isOpen())
return;
// Look for things to do
for (SelectionKey key: selector.selectedKeys())
{
{
SocketChannel channel=null;
try
{
if (!key.isValid())
@ -641,7 +652,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
SelectChannelEndPoint endpoint = createEndPoint(channel,key);
key.attach(endpoint);
if (key.isReadable())
endpoint.schedule();
endpoint.schedule();
}
key = null;
}
@ -665,15 +676,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
LOG.debug(e2);
}
if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())
key.cancel();
}
}
// Everything always handled
selector.selectedKeys().clear();
now=System.currentTimeMillis();
_timeout.setNow(now);
Task task = _timeout.expired();
@ -688,11 +699,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
if (now-_idleTick>__IDLE_TICK)
{
_idleTick=now;
final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
:now;
dispatch(new Runnable()
{
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)
@ -721,130 +742,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
_selecting=null;
}
}
/* ------------------------------------------------------------ */
private void checkJvmBugs(long before, long now, long wait, int selected)
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()
private void renewSelector()
{
try
{
@ -876,7 +777,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
throw new RuntimeException("recreating selector",e);
}
}
/* ------------------------------------------------------------ */
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.
*
*
* @param 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");
_timeout.schedule(task, timeoutMs);
}
/* ------------------------------------------------------------ */
public void cancelTimeout(Timeout.Task task)
{
@ -927,23 +828,24 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
renewSelector();
}
});
renewSelector();
}
}
/* ------------------------------------------------------------ */
private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException
{
SelectChannelEndPoint endp = newEndPoint(channel,this,sKey);
endPointOpened(endp);
endPointOpened(endp);
_endPoints.put(endp,this);
return endp;
}
/* ------------------------------------------------------------ */
public void destroyEndPoint(SelectChannelEndPoint endp)
{
LOG.debug("destroyEndPoint {}",endp);
_endPoints.remove(endp);
endPointClosed(endp);
}
@ -953,11 +855,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
return _selector;
}
/* ------------------------------------------------------------ */
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
try
{
@ -994,8 +896,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
}
}
_timeout.cancelAll();
try
{
@ -1006,7 +908,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
catch (IOException e)
{
LOG.ignore(e);
}
}
_selector=null;
}
}
@ -1021,9 +923,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
public void dump(Appendable out, String indent) throws IOException
{
out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_setID)).append("\n");
Thread selecting = _selecting;
Object where = "not selecting";
StackTraceElement[] trace =selecting==null?null:selecting.getStackTrace();
if (trace!=null)
@ -1037,28 +939,32 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
Selector selector=_selector;
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
dump.add(where);
final CountDownLatch latch = new CountDownLatch(1);
addChange(new Runnable(){
public void run()
if (selector!=null)
{
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
dump.add(where);
final CountDownLatch latch = new CountDownLatch(1);
addChange(new ChangeTask()
{
dumpKeyState(dump);
latch.countDown();
public void run()
{
dumpKeyState(dump);
latch.countDown();
}
});
try
{
latch.await(5,TimeUnit.SECONDS);
}
});
try
{
latch.await(5,TimeUnit.SECONDS);
catch(InterruptedException e)
{
LOG.ignore(e);
}
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 Object _attachment;
public ChannelAndAttachment(SelectableChannel channel, Object attachment)
{
super();
@ -1101,12 +1007,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_deferringInterestedOps0 = deferringInterestedOps0;
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private interface ChangeTask extends Runnable
{}
}

View File

@ -14,9 +14,15 @@
package org.eclipse.jetty.io;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import org.eclipse.jetty.util.IO;
import org.junit.Test;
@ -42,4 +48,88 @@ public class IOTest
out.toString(),
"The quick brown fox jumped over the lazy dog");
}
@Test
public void testHalfCloses() throws Exception
{
ServerSocket connector = new ServerSocket(0);
Socket client = new Socket("localhost",connector.getLocalPort());
System.err.println(client);
Socket server = connector.accept();
System.err.println(server);
// we can write both ways
client.getOutputStream().write(1);
assertEquals(1,server.getInputStream().read());
server.getOutputStream().write(1);
assertEquals(1,client.getInputStream().read());
// shutdown output results in read -1
client.shutdownOutput();
assertEquals(-1,server.getInputStream().read());
// Even though EOF has been read, the server input is not seen as shutdown
assertFalse(server.isInputShutdown());
// and we can read -1 again
assertEquals(-1,server.getInputStream().read());
// but cannot write
try { client.getOutputStream().write(1); assertTrue(false); } catch (SocketException e) {}
// but can still write in opposite direction.
server.getOutputStream().write(1);
assertEquals(1,client.getInputStream().read());
// server can shutdown input to match the shutdown out of client
server.shutdownInput();
// now we EOF instead of reading -1
try { server.getInputStream().read(); assertTrue(false); } catch (SocketException e) {}
// but can still write in opposite direction.
server.getOutputStream().write(1);
assertEquals(1,client.getInputStream().read());
// client can shutdown input
client.shutdownInput();
// now we EOF instead of reading -1
try { client.getInputStream().read(); assertTrue(false); } catch (SocketException e) {}
// But we can still write at the server (data which will never be read)
server.getOutputStream().write(1);
// and the server output is not shutdown
assertFalse( server.isOutputShutdown() );
// until we explictly shut it down
server.shutdownOutput();
// and now we can't write
try { server.getOutputStream().write(1); assertTrue(false); } catch (SocketException e) {}
// but the sockets are still open
assertFalse(client.isClosed());
assertFalse(server.isClosed());
// but if we close one end
client.close();
// it is seen as closed.
assertTrue(client.isClosed());
// but not the other end
assertFalse(server.isClosed());
// which has to be closed explictly
server.close();
assertTrue(server.isClosed());
}
}

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.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -31,7 +30,6 @@ import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
@ -53,17 +51,8 @@ import org.eclipse.jetty.util.log.Logger;
* <p><h4>Notes</h4>
* <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
{
private final static Logger __log=NamingUtil.__log;
@ -101,123 +90,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
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
@ -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;
}
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
@ -435,8 +303,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
ne.setRemainingName(name);
throw ne;
}
Name cname = toCanonicalName (name);
@ -521,7 +387,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
/*------------------------------------------------*/
/**
* Not supported
*
*
* @param name name of subcontext to remove
* @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
* @exception NamingException if an error occurs
@ -1128,7 +994,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
ctx = binding.getObject();
if (ctx instanceof Reference)
{
//deference the object
@ -1154,8 +1019,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else
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
* @exception NamingException if an error occurs
*/ public void rename(String oldName,
String newName)
throws NamingException
{
throw new OperationNotSupportedException();
}
String newName)
throws NamingException
{
throw new OperationNotSupportedException();
}
@ -1247,9 +1111,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
*/
public void close ()
throws NamingException
{
{
}
@ -1362,7 +1224,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name a <code>Name</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();
Binding binding=new Binding (key, obj);
@ -1394,7 +1256,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name a <code>Name</code> value
* @return a <code>Binding</code> value
*/
protected Binding getBinding (Name name)
public Binding getBinding (Name name)
{
return (Binding) _bindings.get(name.toString());
}
@ -1407,13 +1269,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name as a String
* @return null or the Binding
*/
protected Binding getBinding (String name)
public Binding getBinding (String name)
{
return (Binding) _bindings.get(name);
}
/*------------------------------------------------*/
protected void removeBinding (Name name)
public void removeBinding (Name name)
{
String key = name.toString();
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))
return false;

View File

@ -67,8 +67,7 @@ public class javaRootURLContext implements Context
try
{
__javaNameParser = new javaNameParser();
__nameRoot = new NamingContext();
__nameRoot.setNameParser(__javaNameParser);
__nameRoot = new NamingContext(null,null,null,__javaNameParser);
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());

View File

@ -12,11 +12,19 @@
// ========================================================================
package org.eclipse.jetty.jndi.java;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
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.junit.After;
@ -31,13 +39,152 @@ import static org.junit.Assert.fail;
*/
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
public void tearDown() throws Exception
{
InitialContext ic = new InitialContext();
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
public void testLocal () throws Exception
{

View File

@ -84,7 +84,8 @@ public class NestedConnection extends HttpConnection
{
getServer().handle(this);
completeResponse();
_generator.flushBuffer();
while (!_generator.isComplete() && _endp.isOpen())
_generator.flushBuffer();
_endp.flush();
}
finally

View File

@ -4,29 +4,25 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.nested;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.bio.StreamEndPoint;
public class NestedEndPoint extends StreamEndPoint
{
private final HttpServletRequest _outerRequest;
public NestedEndPoint(HttpServletRequest outerRequest, HttpServletResponse outerResponse)
throws IOException
{
@ -65,7 +61,6 @@ public class NestedEndPoint extends StreamEndPoint
@Override
public String getRemoteHost()
{
// TODO Auto-generated method stub
return _outerRequest.getRemoteHost();
}
@Override

View File

@ -43,7 +43,7 @@ public class NestedGenerator extends AbstractGenerator
public void addContent(Buffer content, boolean last) throws IOException
{
// LOG.debug("addContent {} {}",content.length(),last);
LOG.debug("addContent {} {}",content.length(),last);
if (_noContent)
{
content.clear();
@ -70,7 +70,6 @@ public class NestedGenerator extends AbstractGenerator
// Handle any unfinished business?
if (_content != null && _content.length() > 0)
{
flushBuffer();
if (_content != null && _content.length() > 0)
throw new IllegalStateException("FULL");
@ -86,20 +85,22 @@ public class NestedGenerator extends AbstractGenerator
content.clear();
_content = null;
}
else
else if (!last || _buffer!=null)
{
// Yes - so we better check we have a buffer
initContent();
initBuffer();
// Copy _content to buffer;
int len = 0;
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)
{
len--;
_buffer.setPutIndex(_buffer.putIndex() - 1);
}
LOG.debug("copied {} to buffer",len);
_content.skip(len);
@ -139,7 +140,7 @@ public class NestedGenerator extends AbstractGenerator
return false;
// we better check we have a buffer
initContent();
initBuffer();
// 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)
{
@ -176,7 +177,7 @@ public class NestedGenerator extends AbstractGenerator
@Override
public int prepareUncheckedAddContent() throws IOException
{
initContent();
initBuffer();
return _buffer.space();
}
@ -229,6 +230,26 @@ public class NestedGenerator extends AbstractGenerator
_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
public long flushBuffer() throws IOException
@ -236,23 +257,44 @@ public class NestedGenerator extends AbstractGenerator
if (_state == STATE_HEADER)
throw new IllegalStateException("State==HEADER");
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
{
initContent();
_buffer.put(_content);
_content.clear();
_content = null;
}
int len = 0;
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();
int len = _buffer==null?0:_endp.flush(_buffer);
LOG.debug("flushBuffer {} of {}",len,size);
if (len>0)
_buffer.skip(len);
if (_content!=null && _content.length()==0)
_content=null;
if (_buffer!=null && _buffer.length()==0 && _content==null)
{
_buffers.returnBuffer(_buffer);
_buffer=null;
}
if (_state==STATE_FLUSHING && _buffer==null && _content==null)
_state=STATE_END;
return len;
}

View File

@ -428,7 +428,6 @@ public class MongoSessionManager extends NoSqlSessionManager
return o;
}
bout.reset();
out.reset();
out.writeUnshared(value);
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;
import java.io.File;
import java.io.FileInputStream;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
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.Logger;
/**
* PropertyFileLoginModule
*
*
*
*
*/
public class PropertyFileLoginModule extends AbstractLoginModule
{
public static final String DEFAULT_FILENAME = "realm.properties";
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
public static final String DEFAULT_FILENAME = "realm.properties";
public static final Map<String, Map<String, UserInfo>> fileMap = new HashMap<String, Map<String, UserInfo>>();
private String propertyFileName;
private static Map<String, PropertyUserStore> _propertyUserStores = new HashMap<String, PropertyUserStore>();
/**
private int _refreshInterval = 0;
private String _filename = DEFAULT_FILENAME;
/**
* 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 callbackHandler
* @param sharedState
* @param options
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String,?> sharedState, Map<String,?> options)
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
{
super.initialize(subject, callbackHandler, sharedState, options);
loadProperties((String)options.get("file"));
super.initialize(subject,callbackHandler,sharedState,options);
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 &&
credentials!=null && credentials.length()>0)
{
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)
private void setupPropertyUserStore(Map<String, ?> options)
{
if (_propertyUserStores.get(_filename) == null)
{
LOG.warn("Error loading properties from file", e);
throw new RuntimeException(e);
parseConfig(options);
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);
}
}
/**
* Don't implement this as we want to pre-fetch all of the
* users.
* @param username
private void parseConfig(Map<String, ?> options)
{
_filename = (String)options.get("file") != null?(String)options.get("file"):DEFAULT_FILENAME;
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
*/
public UserInfo getUserInfo (String username) throws Exception
public UserInfo getUserInfo(String userName) throws Exception
{
Map<?, ?> userInfoMap = (Map<?, ?>)fileMap.get(propertyFileName);
if (userInfoMap == null)
PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename);
if (propertyUserStore == null)
throw new IllegalStateException("PropertyUserStore should never be null here!");
UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
if(userIdentity==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>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${servlet.spec.groupId}</groupId>
<artifactId>${servlet.spec.artifactId}</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<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
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.rewrite.handler;
@ -19,25 +19,24 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
/* ------------------------------------------------------------ */
/**
*<p> Rewrite handler is responsible for managing the rules. Its capabilities
* 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
* whenever the rule finds a match.
*
* <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
* 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
* whenever the rule finds a match.
*
* <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 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
* (e.g., by virtual host name)
*
*
* <p>The list of predefined rules is:
* <ul>
* <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 RewritePatternRule} - rewrites the requested URI. </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 LegacyRule} - the old version of rewrite. </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>
* </ul>
*
*
*
* Here is a typical jetty.xml configuration would be: <pre>
*
*
* &lt;Set name="handler"&gt;
* &lt;New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"&gt;
* &lt;Set name="rules"&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;Set name="pattern"&gt;/*&lt;/Set&gt;
* &lt;Set name="replacement"&gt;/test&lt;/Set&gt;
* &lt;/New&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;Set name="pattern"&gt;/session/&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;/Item&gt;
*
* &lt;Item&gt;
* &lt;Item&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="name"&gt;server&lt;/Set&gt;
@ -83,7 +90,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt;
* &lt;/Item&gt;
*
* &lt;Item&gt;
* &lt;Item&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="name"&gt;title&lt;/Set&gt;
@ -91,28 +98,28 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt;
* &lt;/Item&gt;
*
* &lt;Item&gt;
* &lt;Item&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="location"&gt;http://jetty.eclipse.org&lt;/Set&gt;
* &lt;/New&gt;
* &lt;/Item&gt;
*
* &lt;Item&gt;
* &lt;Item&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="replacement"&gt;/demo&lt;/Set&gt;
* &lt;/New&gt;
* &lt;/Item&gt;
*
* &lt;Item&gt;
*
* &lt;Item&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="headerValue"&gt;https&lt;/Set&gt;
* &lt;Set name="scheme"&gt;https&lt;/Set&gt;
* &lt;/New&gt;
* &lt;/Item&gt;
*
*
* &lt;Item&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;/Arg&gt;
* &lt;/Call&gt;
*
*
* &lt;/New&gt;
* &lt;/ Item&gt;
*
*
* &lt;/Array&gt;
* &lt;/Set&gt;
*
@ -162,13 +169,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &lt;/New&gt;
* &lt;/Set&gt;
* </pre>
*
*
*/
public class RewriteHandler extends HandlerWrapper
{
private RuleContainer _rules;
/* ------------------------------------------------------------ */
public RewriteHandler()
{
@ -179,7 +186,7 @@ public class RewriteHandler extends HandlerWrapper
/**
* To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
* originalPathAttribute
*
*
* @param legacyRule old style rewrite rule
*/
@Deprecated
@ -201,7 +208,7 @@ public class RewriteHandler extends HandlerWrapper
/* ------------------------------------------------------------ */
/**
* Assigns the rules to process.
* @param rules an array of {@link Rule}.
* @param rules an array of {@link Rule}.
*/
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
{
if (isStarted())
{
{
String returned = _rules.matchAndApply(target, request, response);
target = (returned == null) ? target : returned;
if (!baseRequest.isHandled())
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 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;

View File

@ -13,21 +13,12 @@
package org.eclipse.jetty.security;
import java.io.File;
import java.io.FilenameFilter;
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.security.PropertyUserStore.UserListener;
import org.eclipse.jetty.server.UserIdentity;
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.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -36,27 +27,24 @@ import org.eclipse.jetty.util.resource.Resource;
/**
* Properties User Realm.
*
* An implementation of UserRealm that stores users and roles in-memory in
* HashMaps.
* An implementation of UserRealm that stores users and roles in-memory in HashMaps.
* <P>
* 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:
* 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:
*
* <PRE>
* username: password [,rolename ...]
* </PRE>
*
* Passwords may be clear text, obfuscated or checksummed. The class
* com.eclipse.Util.Password should be used to generate obfuscated passwords or
* password checksums.
* Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
* checksums.
*
* If DIGEST Authentication is used, the password must be in a recoverable
* format, either plain text or OBF:.
* If DIGEST Authentication is used, the password must be in a recoverable 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 PropertyUserStore _propertyUserStore;
private String _config;
private Resource _configResource;
private Scanner _scanner;
@ -72,14 +60,14 @@ public class HashLoginService extends MappedLoginService
{
setName(name);
}
/* ------------------------------------------------------------ */
public HashLoginService(String name, String config)
{
setName(name);
setConfig(config);
}
/* ------------------------------------------------------------ */
public String getConfig()
{
@ -89,7 +77,7 @@ public class HashLoginService extends MappedLoginService
/* ------------------------------------------------------------ */
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
* to password specs followed by an optional comma separated list of role
* names.
* Load realm users from properties file. The property file maps usernames 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)
{
@ -129,52 +116,14 @@ public class HashLoginService extends MappedLoginService
{
return null;
}
/* ------------------------------------------------------------ */
@Override
public void loadUsers() throws IOException
{
if (_config==null)
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();
}
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
@ -183,54 +132,17 @@ public class HashLoginService extends MappedLoginService
{
super.doStart();
if (getRefreshInterval() > 0)
if (_propertyUserStore == null)
{
_scanner = new Scanner();
_scanner.setScanInterval(getRefreshInterval());
List<File> dirList = new ArrayList<File>(1);
dirList.add(_configResource.getFile());
_scanner.setScanDirs(dirList);
_scanner.setFilenameFilter(new FilenameFilter()
if(LOG.isDebugEnabled())
{
public boolean accept(File dir, String name)
{
File f = new File(dir, name);
try
{
if (f.compareTo(_configResource.getFile()) == 0) return true;
}
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();
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
}
_propertyUserStore = new PropertyUserStore();
_propertyUserStore.setRefreshInterval(_refreshInterval);
_propertyUserStore.setConfig(_config);
_propertyUserStore.registerUserListener(this);
_propertyUserStore.start();
}
}
@ -241,9 +153,24 @@ public class HashLoginService extends MappedLoginService
protected void doStop() throws Exception
{
super.doStop();
if (_scanner != null) _scanner.stop();
if (_scanner != null)
_scanner.stop();
_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;
import java.security.Principal;
import javax.security.auth.Subject;
import org.eclipse.jetty.http.security.Credential;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;

View File

@ -3,7 +3,9 @@ package org.eclipse.jetty.security;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -11,7 +13,12 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
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.util.Scanner;
import org.eclipse.jetty.util.Scanner.BulkListener;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -42,8 +49,10 @@ public class PropertyUserStore extends AbstractLifeCycle
private Scanner _scanner;
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 final List<String> _knownUsers = new ArrayList<String>();
private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
private List<UserListener> _listeners;
/* ------------------------------------------------------------ */
@ -57,6 +66,12 @@ public class PropertyUserStore extends AbstractLifeCycle
{
_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;
if (roles != null && roles.length() > 0)
{
roleArray = roles.split(",");
}
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();
if (!known.contains(user))
{
_knownUserIdentities.remove(user);
notifyRemove(user);
}
}
@ -201,15 +237,17 @@ public class PropertyUserStore extends AbstractLifeCycle
_scanner.addListener(new BulkListener()
{
public void filesChanged(List filenames) throws Exception
public void filesChanged(List<String> filenames) throws Exception
{
if (filenames == null)
return;
if (filenames.isEmpty())
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;
if (credentials != null)
{
credentials = credentials.substring(credentials.indexOf(' ')+1);
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
int i = credentials.indexOf(':');
if (i>0)
{
int space=credentials.indexOf(' ');
if (space>0)
{
String username = credentials.substring(0,i);
String password = credentials.substring(i+1);
UserIdentity user = _loginService.login(username,password);
if (user!=null)
String method=credentials.substring(0,space);
if ("basic".equalsIgnoreCase(method))
{
renewSessionOnAuthentication(request,response);
return new UserAuthentication(getAuthMethod(),user);
credentials = credentials.substring(space+1);
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.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.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) $
*
* 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"
*/
public class DigestAuthenticator extends LoginAuthenticator
{
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()
{
super();
@ -69,19 +87,22 @@ public class DigestAuthenticator extends LoginAuthenticator
String mna=configuration.getInitParameter("maxNonceAge");
if (mna!=null)
_maxNonceAge=Long.valueOf(mna);
_maxNonceAgeMs=Long.valueOf(mna);
}
/* ------------------------------------------------------------ */
public String getAuthMethod()
{
return Constraint.__DIGEST_AUTH;
}
/* ------------------------------------------------------------ */
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
{
return true;
}
/* ------------------------------------------------------------ */
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
{
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)
{
@ -170,8 +191,8 @@ public class DigestAuthenticator extends LoginAuthenticator
+ domain
+ "\", nonce=\""
+ newNonce((Request)request)
+ "\", algorithm=MD5, qop=\"auth\""
+ (_useStale ? (" stale=" + stale) : ""));
+ "\", algorithm=MD5, qop=\"auth\","
+ " stale=" + stale);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return Authentication.SEND_CONTINUE;
@ -186,87 +207,59 @@ public class DigestAuthenticator extends LoginAuthenticator
}
/* ------------------------------------------------------------ */
public String newNonce(Request request)
{
long ts=request.getTimeStamp();
long sk = _nonceSecret;
byte[] nounce = new byte[24];
for (int i = 0; i < 8; i++)
Nonce nonce;
do
{
nounce[i] = (byte) (ts & 0xff);
ts = ts >> 8;
nounce[8 + i] = (byte) (sk & 0xff);
sk = sk >> 8;
}
byte[] nounce = new byte[24];
_random.nextBytes(nounce);
byte[] hash = null;
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(nounce, 0, 16);
hash = md.digest();
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
}
catch (Exception e)
{
LOG.warn(e);
}
for (int i = 0; i < hash.length; i++)
{
nounce[8 + i] = hash[i];
if (i == 23) break;
}
return new String(B64Code.encode(nounce));
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
_nonceQueue.add(nonce);
return nonce._nonce;
}
/**
* @param nonce nonce to check
* @param nstring nonce to check
* @param request
* @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
{
byte[] n = B64Code.decode(nonce.toCharArray());
if (n.length != 24) return -1;
long ts = 0;
long sk = _nonceSecret;
byte[] n2 = new byte[16];
System.arraycopy(n, 0, n2, 0, 8);
for (int i = 0; i < 8; i++)
{
n2[8 + i] = (byte) (sk & 0xff);
sk = sk >> 8;
ts = (ts << 8) + (0xff & (long) n[7 - i]);
}
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
nonce = _nonceCount.get(digest.nonce);
if (nonce==null)
return 0;
long count = Long.parseLong(digest.nc,16);
if (count>Integer.MAX_VALUE)
return 0;
int old=nonce._nc.get();
while (!nonce._nc.compareAndSet(old,(int)count))
old=nonce._nc.get();
if (count<=old)
return -1;
return 1;
}
catch (Exception e)
@ -276,18 +269,21 @@ public class DigestAuthenticator extends LoginAuthenticator
return -1;
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private static class Digest extends Credential
{
private static final long serialVersionUID = -2484639019549527724L;
String method = null;
String username = null;
String realm = null;
String nonce = null;
String nc = null;
String cnonce = null;
String qop = null;
String uri = null;
String response = null;
final String method;
String username = "";
String realm = "";
String nonce = "";
String nc = "";
String cnonce = "";
String qop = "";
String uri = "";
String response = "";
/* ------------------------------------------------------------ */
Digest(String m)

View File

@ -201,13 +201,13 @@ public class ConstraintTest
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
@ -218,20 +218,20 @@ public class ConstraintTest
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 403 "));
assertTrue(response.indexOf("!role") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
@ -490,18 +490,18 @@ public class ConstraintTest
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 403"));
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
@ -512,20 +512,20 @@ public class ConstraintTest
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 403 "));
assertTrue(response.indexOf("!role") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
@ -776,7 +776,7 @@ public class ConstraintTest
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
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");
assertTrue(response.startsWith("HTTP/1.1 500 "));
@ -789,7 +789,7 @@ public class ConstraintTest
_server.start();
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
}
@ -809,13 +809,13 @@ public class ConstraintTest
assertTrue(response.indexOf("user=null") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
assertTrue(response.indexOf("user=null") > 0);
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");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
assertTrue(response.indexOf("user=admin") > 0);

View File

@ -78,6 +78,9 @@ public class PropertyUserStoreTest
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());
}
@ -117,7 +120,11 @@ public class PropertyUserStoreTest
long start = System.currentTimeMillis();
while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000)
{
Thread.sleep(10);
}
Assert.assertNotNull("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip"));
Assert.assertEquals(4,userCount.get());
Assert.assertTrue(users.contains("skip"));

View File

@ -112,5 +112,11 @@
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -7,12 +7,18 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.ChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class AsyncHttpConnection extends HttpConnection
{
private final static int NO_PROGRESS_INFO = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_INFO",100);
private final static int NO_PROGRESS_CLOSE = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_CLOSE",200);
private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
private int _total_no_progress;
public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
@ -22,21 +28,21 @@ public class AsyncHttpConnection extends HttpConnection
public Connection handle() throws IOException
{
Connection connection = this;
boolean some_progress=false;
boolean progress=true;
// Loop while more in buffer
try
{
setCurrentConnection(this);
boolean progress=true;
boolean more_in_buffer =false;
while (_endp.isOpen() && (more_in_buffer || progress))
while (_endp.isOpen() && (more_in_buffer || progress) && connection==this)
{
progress=false;
try
{
LOG.debug("async request",_request);
// Handle resumed request
if (_request._async.isAsync() && !_request._async.isComplete())
@ -53,6 +59,11 @@ public class AsyncHttpConnection extends HttpConnection
// Flush output from buffering endpoint
if (_endp.isBufferingOutput())
_endp.flush();
// Special case close handling.
// If we were dispatched and have made no progress, but io is shutdown, then close
if (!progress && !some_progress && (_endp.isInputShutdown()||_endp.isOutputShutdown()))
_endp.close();
}
catch (HttpException e)
{
@ -88,7 +99,7 @@ public class AsyncHttpConnection extends HttpConnection
{
_parser.reset();
_generator.reset(true);
return switched;
connection=switched;
}
}
@ -98,7 +109,6 @@ public class AsyncHttpConnection extends HttpConnection
reset(false);
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
}
// else Are we suspended?
else if (_request.isAsyncStarted())
{
@ -108,6 +118,8 @@ public class AsyncHttpConnection extends HttpConnection
}
else
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
some_progress|=progress|((SelectChannelEndPoint)_endp).isProgressing();
}
}
}
@ -115,12 +127,31 @@ public class AsyncHttpConnection extends HttpConnection
{
setCurrentConnection(null);
_parser.returnBuffers();
_generator.returnBuffers();
// Are we write blocked
if (_generator.isCommitted() && !_generator.isComplete())
((AsyncEndPoint)_endp).scheduleWrite();
else
_generator.returnBuffers();
// Check if we are write blocked
if (_generator.isCommitted() && !_generator.isComplete() && _endp.isOpen() && !_endp.isOutputShutdown())
((AsyncEndPoint)_endp).scheduleWrite(); // TODO. This should not be required
if (!some_progress)
{
_total_no_progress++;
if (NO_PROGRESS_INFO>0 && _total_no_progress%NO_PROGRESS_INFO==0 && (NO_PROGRESS_CLOSE<=0 || _total_no_progress< NO_PROGRESS_CLOSE))
{
LOG.info("EndPoint making no progress: "+_total_no_progress+" "+_endp);
}
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());
}
}
}
}
return connection;
}

View File

@ -76,9 +76,8 @@ public class BlockingHttpConnection extends HttpConnection
LOG.debug(e);
}
_generator.sendError(e.getStatus(), e.getReason(), null, true);
_parser.reset();
_endp.close();
_endp.shutdownOutput();
}
finally
{

View File

@ -205,6 +205,7 @@ public class Dispatcher implements RequestDispatcher
if (!(response instanceof HttpServletResponse))
response = new ServletResponseHttpWrapper(response);
final boolean old_handled=baseRequest.isHandled();
final String old_uri=baseRequest.getRequestURI();
final String old_context_path=baseRequest.getContextPath();
final String old_servlet_path=baseRequest.getServletPath();
@ -216,6 +217,7 @@ public class Dispatcher implements RequestDispatcher
try
{
baseRequest.setHandled(false);
baseRequest.setDispatcherType(dispatch);
if (_named!=null)
@ -262,6 +264,8 @@ public class Dispatcher implements RequestDispatcher
baseRequest.setRequestURI(_uri);
baseRequest.setContextPath(_contextHandler.getContextPath());
baseRequest.setServletPath(null);
baseRequest.setPathInfo(_uri);
baseRequest.setAttributes(attr);
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
@ -286,6 +290,7 @@ public class Dispatcher implements RequestDispatcher
}
finally
{
baseRequest.setHandled(old_handled);
baseRequest.setRequestURI(old_uri);
baseRequest.setContextPath(old_context_path);
baseRequest.setServletPath(old_servlet_path);

View File

@ -327,7 +327,7 @@ public abstract class HttpConnection extends AbstractConnection
}
if (_in == null)
_in = new HttpInput(((HttpParser)_parser),_connector.getMaxIdleTime());
_in = new HttpInput(HttpConnection.this);
return _in;
}
@ -455,22 +455,22 @@ public abstract class HttpConnection extends AbstractConnection
{
async_exception=e;
LOG.debug(e);
_request.setHandled(true);
error=true;
_request.setHandled(true);
}
catch (UncheckedIOException e)
{
async_exception=e;
LOG.debug(e);
_request.setHandled(true);
error=true;
_request.setHandled(true);
}
catch (HttpException e)
{
LOG.debug(e);
error=true;
_request.setHandled(true);
_response.sendError(e.getStatus(), e.getReason());
error=true;
}
catch (Throwable e)
{
@ -478,9 +478,8 @@ public abstract class HttpConnection extends AbstractConnection
throw (ThreadDeath)e;
async_exception=e;
error=true;
LOG.warn(String.valueOf(_uri),e);
error=true;
_request.setHandled(true);
_generator.sendError(info==null?400:500, null, null, true);
}
@ -515,7 +514,12 @@ public abstract class HttpConnection extends AbstractConnection
if(_endp.isOpen())
{
if (error)
{
_endp.shutdownOutput();
_generator.setPersistent(false);
if (!_generator.isComplete())
_response.complete();
}
else
{
if (!_response.isCommitted() && !_request.isHandled())
@ -677,6 +681,16 @@ public abstract class HttpConnection extends AbstractConnection
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 +980,7 @@ public abstract class HttpConnection extends AbstractConnection
{
Output()
{
super((AbstractGenerator)HttpConnection.this._generator,
_connector.isLowResources()?_connector.getLowResourceMaxIdleTime():_connector.getMaxIdleTime());
super(HttpConnection.this);
}
/* ------------------------------------------------------------ */

View File

@ -22,14 +22,14 @@ import org.eclipse.jetty.io.Buffer;
public class HttpInput extends ServletInputStream
{
protected final HttpConnection _connection;
protected final HttpParser _parser;
protected final long _maxIdleTime;
/* ------------------------------------------------------------ */
public HttpInput(HttpParser parser, long maxIdleTime)
public HttpInput(HttpConnection connection)
{
_parser=parser;
_maxIdleTime=maxIdleTime;
_connection=connection;
_parser=(HttpParser)connection.getParser();
}
/* ------------------------------------------------------------ */
@ -40,7 +40,7 @@ public class HttpInput extends ServletInputStream
public int read() throws IOException
{
int c=-1;
Buffer content=_parser.blockForContent(_maxIdleTime);
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
if (content!=null)
c= 0xff & content.get();
return c;
@ -54,7 +54,7 @@ public class HttpInput extends ServletInputStream
public int read(byte[] b, int off, int len) throws IOException
{
int l=-1;
Buffer content=_parser.blockForContent(_maxIdleTime);
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
if (content!=null)
l= content.get(b, off, len);
return l;

View File

@ -36,9 +36,8 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
*/
public class HttpOutput extends ServletOutputStream
{
protected final HttpConnection _connection;
protected final AbstractGenerator _generator;
protected final long _maxIdleTime;
protected final ByteArrayBuffer _buf = new ByteArrayBuffer(AbstractGenerator.NO_BYTES);
private boolean _closed;
// These are held here for reuse by Writer
@ -46,15 +45,20 @@ public class HttpOutput extends ServletOutputStream
Writer _converter;
char[] _chars;
ByteArrayOutputStream2 _bytes;
/* ------------------------------------------------------------ */
public HttpOutput(AbstractGenerator generator, long maxIdleTime)
public HttpOutput(HttpConnection connection)
{
_generator=generator;
_maxIdleTime=maxIdleTime;
_connection=connection;
_generator=(AbstractGenerator)connection.getGenerator();
}
/* ------------------------------------------------------------ */
public int getMaxIdleTime()
{
return _connection.getMaxIdleTime();
}
/* ------------------------------------------------------------ */
public boolean isWritten()
{
@ -87,7 +91,7 @@ public class HttpOutput extends ServletOutputStream
@Override
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.
while (_generator.isBufferFull())
{
_generator.blockForOutput(_maxIdleTime);
_generator.blockForOutput(getMaxIdleTime());
if (_closed)
throw new IOException("Closed");
if (!_generator.isOpen())
@ -152,7 +156,7 @@ public class HttpOutput extends ServletOutputStream
// Block until we can add _content.
while (_generator.isBufferFull())
{
_generator.blockForOutput(_maxIdleTime);
_generator.blockForOutput(getMaxIdleTime());
if (_closed)
throw new IOException("Closed");
if (!_generator.isOpen())
@ -175,7 +179,7 @@ public class HttpOutput extends ServletOutputStream
// Block until our buffer is free
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.Connection;
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
{
private static final Logger LOG = Log.getLogger(LocalConnector.class);
private final BlockingQueue<Request> _requests = new LinkedBlockingQueue<Request>();
public LocalConnector()
@ -135,8 +138,14 @@ public class LocalConnector extends AbstractConnector
}
}
}
catch (IOException x)
{
LOG.debug(x);
leaveOpen = false;
}
catch (Exception x)
{
LOG.warn(x);
leaveOpen = false;
}
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()
{
if (_baseParameters == null)
_baseParameters = new MultiMap(16);
if (_paramsExtracted)
{
if (_parameters==null)
_parameters=_baseParameters;
return;
}
_paramsExtracted = true;
// Handle query string
if (_uri!=null && _uri.hasQuery())
try
{
if (_queryEncoding==null)
_uri.decodeQueryTo(_baseParameters);
else
// Handle query string
if (_uri!=null && _uri.hasQuery())
{
try
{
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
}
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)
if (_queryEncoding==null)
_uri.decodeQueryTo(_baseParameters);
else
{
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);
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
}
catch (IOException e)
catch (UnsupportedEncodingException e)
{
if (LOG.isDebugEnabled())
LOG.warn(e);
@ -283,23 +240,75 @@ public class Request implements HttpServletRequest
}
}
}
}
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())
// handle any _content.
String encoding = getCharacterEncoding();
String content_type = getContentType();
if (content_type != null && content_type.length() > 0)
{
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));
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
{
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))
{
buf = _connection.getRequest().getRootURL();
buf.append(canonical);
buf.append(URIUtil.encodePath(canonical));
if (uri.getQuery()!=null)
{
buf.append('?');

View File

@ -17,6 +17,7 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@ -81,7 +82,7 @@ public class SocketConnector extends AbstractConnector
_localPort=_serverSocket.getLocalPort();
if (_localPort<=0)
throw new IllegalStateException("port not allocated for "+this);
}
/* ------------------------------------------------------------ */
@ -175,7 +176,6 @@ public class SocketConnector extends AbstractConnector
/* ------------------------------------------------------------------------------- */
protected class ConnectorEndPoint extends SocketEndPoint implements Runnable, ConnectedEndPoint
{
boolean _dispatched=false;
volatile Connection _connection;
protected final Socket _socket;
@ -251,6 +251,12 @@ public class SocketConnector extends AbstractConnector
try{close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (SocketException e)
{
LOG.debug("EOF", e);
try{close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (HttpException e)
{
LOG.debug("BAD", e);
@ -277,7 +283,7 @@ public class SocketConnector extends AbstractConnector
if (!_socket.isClosed())
{
long timestamp=System.currentTimeMillis();
int max_idle=getMaxIdleTime();
int max_idle=getMaxIdleTime();
_socket.setSoTimeout(getMaxIdleTime());
int c=0;

View File

@ -833,7 +833,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
String old_path_info = null;
ClassLoader old_classloader = null;
Thread current_thread = null;
String pathInfo = null;
String pathInfo = target;
DispatcherType dispatch = baseRequest.getDispatcherType();

View File

@ -159,7 +159,7 @@ public class GzipHandler extends HandlerWrapper
*
* @return the buffer size
*/
public int setBufferSize()
public int getBufferSize()
{
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.ByteArrayBuffer;
import org.eclipse.jetty.io.WriterOutputStream;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
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.
* 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
@ -205,7 +206,7 @@ public class ResourceHandler extends AbstractHandler
{
try
{
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-default.css"));
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
}
catch(IOException e)
{
@ -292,10 +293,29 @@ public class ResourceHandler extends AbstractHandler
/* ------------------------------------------------------------ */
protected Resource getResource(HttpServletRequest request) throws MalformedURLException
{
String path_info=request.getPathInfo();
if (path_info==null)
return null;
return getResource(path_info);
String servletPath;
String pathInfo;
Boolean included = request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI) != null;
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
{
@ -334,17 +354,21 @@ public class ResourceHandler extends AbstractHandler
return;
boolean skipContentBody = false;
if(!HttpMethods.GET.equals(request.getMethod()))
{
if(!HttpMethods.HEAD.equals(request.getMethod()))
{
return;
}
skipContentBody = true;
}
Resource resource = getResource(request);
if (resource==null || !resource.exists())
{
if (target.endsWith("/jetty-stylesheet.css"))
if (target.endsWith("/jetty-dir.css"))
{
response.setContentType("text/css");
resource = getStylesheet();
@ -359,7 +383,7 @@ public class ResourceHandler extends AbstractHandler
return;
}
// We are going to server something
// We are going to serve something
baseRequest.setHandled(true);
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);
}
/* ------------------------------------------------------------ */
public SelectorManager getSelectorManager()
{
return _manager;
}
/* ------------------------------------------------------------ */
public Object getConnection()
{

View File

@ -14,7 +14,9 @@
package org.eclipse.jetty.server.session;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -46,6 +48,34 @@ public class HashSessionIdManager extends AbstractSessionIdManager
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.
*

View File

@ -18,6 +18,7 @@ import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -56,6 +57,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
protected final HashSet<String> _sessionIds = new HashSet<String>();
protected Server _server;
protected Driver _driver;
protected String _driverClassName;
protected String _connectionUrl;
protected DataSource _datasource;
@ -184,6 +186,19 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
_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()
{
return _driverClassName;
@ -461,7 +476,11 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
InitialContext ic = new InitialContext();
_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);
}

View File

@ -16,6 +16,8 @@ package org.eclipse.jetty.server.ssl;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
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.Request;
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;
SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
SSLSession sslSession=sslEngine.getSession();
SslCertificates.customize(sslSession,endpoint,request);
}
@ -565,33 +566,19 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
{
SSLEngine engine;
if (channel != null && _sslContextFactory.isSessionCachingEnabled())
if (channel != null)
{
String peerHost = channel.socket().getInetAddress().getHostAddress();
int peerPort = channel.socket().getPort();
engine = _sslContextFactory.getSslContext().createSSLEngine(peerHost, peerPort);
engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
}
else
{
engine = _sslContextFactory.getSslContext().createSSLEngine();
engine = _sslContextFactory.newSslEngine();
}
customizeEngine(engine);
return engine;
}
/* ------------------------------------------------------------ */
private void customizeEngine(SSLEngine engine)
{
engine.setUseClientMode(false);
if (_sslContextFactory.getWantClientAuth())
engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
if (_sslContextFactory.getNeedClientAuth())
engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
engine.setEnabledCipherSuites(
_sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
engine.getSupportedCipherSuites()));
return engine;
}
/* ------------------------------------------------------------ */
@ -601,22 +588,13 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
@Override
protected void doStart() throws Exception
{
if (!_sslContextFactory.checkConfig())
{
throw new IllegalStateException("SSL context is not configured correctly.");
}
_sslContextFactory.checkKeyStore();
_sslContextFactory.start();
SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
SSLEngine sslEngine = _sslContextFactory.newSslEngine();
sslEngine.setUseClientMode(false);
sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
sslEngine.getEnabledCipherSuites(),
sslEngine.getSupportedCipherSuites()));
SSLSession sslSession = sslEngine.getSession();

View File

@ -4,32 +4,30 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.ssl;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.http.ssl.SslContextFactory;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.io.bio.SocketEndPoint;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.bio.SocketConnector;
@ -39,17 +37,17 @@ import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/**
* SSL Socket Connector.
*
*
* This specialization of SocketConnector is an abstract listener that can be used as the basis for a
* specific JSSE listener.
*
* The original of this class was heavily based on the work from Court Demas, which in turn is
*
* The original of this class was heavily based on the work from Court Demas, which in turn is
* based on the work from Forge Research. Since JSSE, this class has evolved significantly from
* that early work.
*
*
* @org.apache.xbean.XBean element="sslSocketConnector" description="Creates an ssl socket connector"
*
*
*
*/
public class SslSocketConnector extends SocketConnector implements SslConnector
{
@ -67,6 +65,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
}
/* ------------------------------------------------------------ */
public SslSocketConnector(SslContextFactory sslContextFactory)
{
_sslContextFactory = sslContextFactory;
@ -85,7 +84,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
/**
* Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
* a vulnerability in SSL/TLS with re-negotiation. If your JVM
* does not have CVE-2009-3555 fixed, then re-negotiation should
* does not have CVE-2009-3555 fixed, then re-negotiation should
* not be allowed.
* @param allowRenegotiate true if re-negotiation is allowed (default false)
*/
@ -98,19 +97,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
@Override
public void accept(int acceptorID)
throws IOException, InterruptedException
{
{
Socket socket = _serverSocket.accept();
configure(socket);
ConnectorEndPoint connection=new SslConnectorEndPoint(socket);
connection.dispatch();
}
/* ------------------------------------------------------------ */
@Override
protected void configure(Socket socket)
throws IOException
{
{
super.configure(socket);
}
@ -129,8 +128,8 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* certificate in the chain is the one set by the client, the next is the one used to
* authenticate the first, and so on. </li>
* </ul>
*
* @param endpoint The Socket the request arrived on.
*
* @param endpoint The Socket the request arrived on.
* This should be a {@link SocketEndPoint} wrapping a {@link SSLSocket}.
* @param request HttpRequest to be customised.
*/
@ -140,7 +139,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
super.customize(endpoint, request);
request.setScheme(HttpSchemes.HTTPS);
SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
SSLSession sslSession = sslSocket.getSession();
@ -148,7 +147,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
SslCertificates.customize(sslSession,endpoint,request);
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
* @deprecated
@ -157,7 +156,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
public String[] getExcludeCipherSuites() {
return _sslContextFactory.getExcludeCipherSuites();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#getIncludeCipherSuites()
@ -186,7 +185,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public String getKeystoreType()
public String getKeystoreType()
{
return _sslContextFactory.getKeyStoreType();
}
@ -208,7 +207,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public String getProtocol()
public String getProtocol()
{
return _sslContextFactory.getProtocol();
}
@ -229,7 +228,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public String getSecureRandomAlgorithm()
public String getSecureRandomAlgorithm()
{
return _sslContextFactory.getSecureRandomAlgorithm();
}
@ -240,7 +239,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public String getSslKeyManagerFactoryAlgorithm()
public String getSslKeyManagerFactoryAlgorithm()
{
return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
}
@ -251,7 +250,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public String getSslTrustManagerFactoryAlgorithm()
public String getSslTrustManagerFactoryAlgorithm()
{
return _sslContextFactory.getTrustManagerFactoryAlgorithm();
}
@ -313,7 +312,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
final int confidentialPort = getConfidentialPort();
return confidentialPort == 0 || confidentialPort == request.getServerPort();
}
/* ------------------------------------------------------------ */
/**
* By default, we're integral, given we speak SSL. But, if we've been told about an integral
@ -329,6 +328,22 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
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}
@ -336,16 +351,12 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
@Override
protected void doStart() throws Exception
{
if (!_sslContextFactory.checkConfig())
{
throw new IllegalStateException("SSL context is not configured correctly.");
}
_sslContextFactory.checkKeyStore();
_sslContextFactory.start();
super.doStart();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.bio.SocketConnector#doStop()
@ -357,14 +368,14 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
super.doStop();
}
/* ------------------------------------------------------------ */
/**
* @param host The host name that this server should listen on
* @param port the port that this server should listen on
* @param port the port that this server should listen on
* @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)}
* @return A new {@link ServerSocket socket object} bound to the supplied address with all other
* settings as per the current configuration of this connector.
* settings as per the current configuration of this connector.
* @see #setWantClientAuth(boolean)
* @see #setNeedClientAuth(boolean)
* @exception IOException
@ -372,22 +383,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
@Override
protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
{
SSLServerSocketFactory factory = _sslContextFactory.getSslContext().getServerSocketFactory();
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;
return _sslContextFactory.newSslServerSocket(host,port,backlog);
}
/* ------------------------------------------------------------ */
@ -440,7 +436,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public void setKeystoreType(String keystoreType)
public void setKeystoreType(String keystoreType)
{
_sslContextFactory.setKeyStoreType(keystoreType);
}
@ -448,7 +444,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
/* ------------------------------------------------------------ */
/**
* Set the value of the needClientAuth property
*
*
* @param needClientAuth true iff we require client certificate authentication.
* @deprecated
*/
@ -457,7 +453,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
_sslContextFactory.setNeedClientAuth(needClientAuth);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
@ -468,7 +464,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
_sslContextFactory.setKeyStorePassword(password);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
@ -486,7 +482,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public void setProtocol(String protocol)
public void setProtocol(String protocol)
{
_sslContextFactory.setProtocol(protocol);
}
@ -507,7 +503,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public void setSecureRandomAlgorithm(String algorithm)
public void setSecureRandomAlgorithm(String algorithm)
{
_sslContextFactory.setSecureRandomAlgorithm(algorithm);
}
@ -518,18 +514,18 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
* @deprecated
*/
@Deprecated
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
{
_sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
* @deprecated
*/
@Deprecated
public void setSslTrustManagerFactoryAlgorithm(String algorithm)
public void setSslTrustManagerFactoryAlgorithm(String algorithm)
{
_sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
}
@ -544,7 +540,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
_sslContextFactory.setTrustStore(truststore);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
@ -555,7 +551,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
_sslContextFactory.setTrustStoreType(truststoreType);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
@ -580,9 +576,9 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
/* ------------------------------------------------------------ */
/**
* Set the value of the _wantClientAuth property. This property is used
* Set the value of the _wantClientAuth property. This property is used
* internally when opening server sockets.
*
*
* @param wantClientAuth true if we want client certificate authentication.
* @see SSLServerSocket#setWantClientAuth
* @deprecated
@ -603,7 +599,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
_handshakeTimeout = msec;
}
/* ------------------------------------------------------------ */
public int getHandshakeTimeout ()
@ -618,19 +614,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
super(socket);
}
@Override
public void shutdownOutput() throws IOException
{
close();
}
@Override
public void shutdownInput() throws IOException
{
close();
}
@Override
public void run()
{
@ -638,7 +634,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
{
int handshakeTimeout = getHandshakeTimeout();
int oldTimeout = _socket.getSoTimeout();
if (handshakeTimeout > 0)
if (handshakeTimeout > 0)
_socket.setSoTimeout(handshakeTimeout);
final SSLSocket ssl=(SSLSocket)_socket;
@ -668,7 +664,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
}
catch (SSLException e)
{
LOG.debug(e);
LOG.debug(e);
try{close();}
catch(IOException e2){LOG.ignore(e2);}
}
@ -677,14 +673,14 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
LOG.debug(e);
try{close();}
catch(IOException e2){LOG.ignore(e2);}
}
}
}
}
/* ------------------------------------------------------------ */
/**
* Unsupported.
*
*
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
* @deprecated
*/
@ -697,7 +693,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
/* ------------------------------------------------------------ */
/**
* Unsupported.
*
*
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
* @deprecated
*/

View File

@ -52,7 +52,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
{
int x=write++&0xff;
if (x<8)
{
clearWritable();
return 0;
}
if (x<32)
return flush(header);
return super.flush(header,buffer,trailer);
@ -67,7 +70,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
{
int x=write++&0xff;
if (x<8)
{
clearWritable();
return 0;
}
if (x<32)
{
View v = new View(buffer);
@ -75,6 +81,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
int l=super.flush(v);
if (l>0)
buffer.skip(l);
clearWritable();
return l;
}
return super.flush(buffer);

View File

@ -37,8 +37,11 @@ import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.io.EndPoint;
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.StdErrLog;
import org.junit.Test;
/**
@ -106,7 +109,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
* Feed the server the entire request at once.
*/
@Test
public void testRequest1_jetty() throws Exception
public void testRequest1() throws Exception
{
configureServer(new HelloWorldHandler());
@ -164,7 +167,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
* Feed the server fragmentary headers and see how it copes with it.
*/
@Test
public void testRequest1Fragments_jetty() throws Exception, InterruptedException
public void testRequest1Fragments() throws Exception, InterruptedException
{
configureServer(new HelloWorldHandler());
@ -197,7 +200,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
@Test
public void testRequest2_jetty() throws Exception
public void testRequest2() throws Exception
{
configureServer(new EchoHandler());
@ -226,7 +229,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
@Test
public void testRequest2Fragments_jetty() throws Exception
public void testRequest2Fragments() throws Exception
{
configureServer(new EchoHandler());
@ -270,7 +273,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
@Test
public void testRequest2Iterate_jetty() throws Exception
public void testRequest2Iterate() throws Exception
{
configureServer(new EchoHandler());
@ -309,7 +312,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
* After several iterations, I generated some known bad fragment points.
*/
@Test
public void testRequest2KnownBad_jetty() throws Exception
public void testRequest2KnownBad() throws Exception
{
configureServer(new EchoHandler());
@ -425,7 +428,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
while(len>=0)
{
Thread.sleep(500);
Thread.sleep(100);
len=is.read(buf);
if (len>0)
total+=len;
@ -447,6 +450,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
long start=System.currentTimeMillis();
Socket client=newSocket(HOST,_connector.getLocalPort());
int total=0;
try
{
OutputStream os=client.getOutputStream();
@ -461,7 +465,6 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
).getBytes());
os.flush();
int total=0;
int len=0;
byte[] buf=new byte[1024*32];
@ -480,6 +483,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
finally
{
System.err.println("Got "+total+" of "+(512*1024));
client.close();
}
}
@ -490,17 +494,17 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
configureServer(new BigBlockHandler());
Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000);
client.setSoTimeout(20000);
try
{
OutputStream os=client.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
os.write((
"GET / HTTP/1.1\r\n"+
"GET /r1 HTTP/1.1\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"\r\n"+
"GET / HTTP/1.1\r\n"+
"GET /r2 HTTP/1.1\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"connection: close\r\n"+
"\r\n"
@ -583,6 +587,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
{
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
@ -598,10 +603,12 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
long[] times=new long[10];
for (int i=0;i<times.length;i++)
{
// System.err.println("\nBLOCK "+request.getRequestURI()+" "+i);
long start=System.currentTimeMillis();
out.write(buf);
long end=System.currentTimeMillis();
times[i]=end-start;
// System.err.println("Block "+request.getRequestURI()+" "+i+" "+times[i]);
}
out.println();
for (long t : times)
@ -910,6 +917,68 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
}
@Test
public void testCommittedError() throws Exception
{
CommittedErrorHandler handler =new CommittedErrorHandler();
configureServer(handler);
Socket client=newSocket(HOST,_connector.getLocalPort());
try
{
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream();
// Send a request
os.write((
"GET / HTTP/1.1\r\n"+
"Host: "+HOST+":"+_connector.getLocalPort()+"\r\n" +
"\r\n"
).getBytes());
os.flush();
client.setSoTimeout(2000);
String in = IO.toString(is);
assertEquals(-1,is.read()); // Closed by error!
assertTrue(in.indexOf("HTTP/1.1 200 OK")>=0);
assertTrue(in.indexOf("Transfer-Encoding: chunked")>0);
assertTrue(in.indexOf("Now is the time for all good men to come to the aid of the party")>0);
assertTrue(in.indexOf("\r\n0\r\n")==-1); // chunking is interrupted by error close
client.close();
Thread.sleep(100);
assertTrue(!handler._endp.isOpen());
}
finally
{
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false);
if (!client.isClosed())
client.close();
}
}
protected static class CommittedErrorHandler extends AbstractHandler
{
public EndPoint _endp;
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
_endp=baseRequest.getConnection().getEndPoint();
response.setHeader("test","value");
response.setStatus(200);
response.setContentType("text/plain");
response.getWriter().println("Now is the time for all good men to come to the aid of the party");
response.getWriter().flush();
response.flushBuffer();
throw new ServletException(new Exception("exception after commit"));
}
}
protected static class AvailableHandler extends AbstractHandler
{
public Exchanger<Object> _ex = new Exchanger<Object>();

View File

@ -12,6 +12,7 @@ import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.ByteArrayEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.SimpleBuffers;
import org.eclipse.jetty.util.StringUtil;
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);
}
@ -158,7 +169,17 @@ public class HttpWriterTest
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);
writer.setCharacterEncoding(StringUtil.__UTF8);

View File

@ -24,12 +24,16 @@ import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
@ -68,7 +72,50 @@ public class RequestTest
_server.stop();
_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
public void testContentTypeEncoding() throws Exception
{

View File

@ -383,31 +383,45 @@ public class ResponseTest
public void testSendRedirect()
throws Exception
{
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(false);
AbstractSessionManager manager=new HashSessionManager();
manager.setSessionIdManager(new HashSessionIdManager());
request.setSessionManager(manager);
request.setSession(new TestSession(manager,"12345"));
manager.setCheckingRemoteSessionIdEncoding(false);
String[][] tests={
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
{"/other/location","http://myhost:8888/other/location"},
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"location","http://myhost:8888/path/location"},
{"./location","http://myhost:8888/path/location"},
{"../location","http://myhost:8888/location"},
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"l%20cation","http://myhost:8888/path/l%20cation"},
{"./l%20cation","http://myhost:8888/path/l%20cation"},
{"../l%20cation","http://myhost:8888/l%20cation"},
};
for (int i=1;i<tests.length;i++)
{
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");
String location = out.getOut().toString();
int l=location.indexOf("Location: ");
int e=location.indexOf('\n',l);
location=location.substring(l+10,e).trim();
assertEquals("http://myhost:8888/other/location;jsessionid=12345",location);
response.sendRedirect(tests[i][0]);
String location = out.getOut().toString();
int l=location.indexOf("Location: ");
int e=location.indexOf('\n',l);
location=location.substring(l+10,e).trim();
assertEquals(tests[i][0],tests[i][1],location);
}
}
@Test

View File

@ -25,10 +25,12 @@ public class SelectChannelServerTest extends HttpServerTestBase
{
startServer(new SelectChannelConnector());
}
@Override
public void testBigBlocks() throws Exception
public void testCommittedError() throws Exception
{
super.testBigBlocks();
super.testCommittedError();
}
}

View File

@ -91,7 +91,7 @@ public class StressTest
_server.setThreadPool(_threads);
_connector = new SelectChannelConnector();
_connector.setAcceptors(Math.max(1, Runtime.getRuntime().availableProcessors() / 2));
_connector.setAcceptors(1);
_connector.setAcceptQueueSize(5000);
_connector.setMaxIdleTime(30000);
_server.addConnector(_connector);
@ -123,7 +123,7 @@ public class StressTest
// TODO needs to be further investigated
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
doThreads(10,100,false);
doThreads(10,10,false);
if (Stress.isEnabled())
{
Thread.sleep(1000);
@ -139,7 +139,7 @@ public class StressTest
// TODO needs to be further investigated
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
doThreads(20,100,true);
doThreads(20,10,true);
if (Stress.isEnabled())
{
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");
}
}

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