Merge branch 'master' into release

This commit is contained in:
Jesse McConnell 2011-10-06 09:16:58 -05:00
commit dd830aae17
158 changed files with 7018 additions and 4023 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,4 +1,7 @@
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-7.5.1.v20110908 - 08 September 2011
+ 350634 Added Resource.newResource(File)

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,8 +88,14 @@ 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);

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

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all-server</artifactId>
<name>Jetty :: Aggregate :: All Server</name>
<properties>
@ -25,7 +24,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

@ -5,10 +5,8 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all</artifactId>
<name>Jetty :: Aggregate :: All core Jetty</name>
<build>
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
<plugins>
@ -22,7 +20,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 +73,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

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-client</artifactId>
<name>Jetty :: Aggregate :: HTTP Client</name>

View File

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-plus</artifactId>
<name>Jetty :: Aggregate :: Plus Server</name>

View File

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-server</artifactId>
<name>Jetty :: Aggregate :: HTTP Server</name>

View File

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-servlet</artifactId>
<name>Jetty :: Aggregate :: Servlet Server</name>

View File

@ -5,7 +5,6 @@
<version>7.5.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-webapp</artifactId>
<name>Jetty :: Aggregate :: WebApp Server</name>
@ -22,7 +21,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

@ -130,6 +130,7 @@ public class Ajp13Generator extends AbstractGenerator
{
return true;
}
/* ------------------------------------------------------------ */
@Override
public void reset(boolean returnBuffers)
@ -142,8 +143,6 @@ public class Ajp13Generator extends AbstractGenerator
_bufferPrepared = false;
_last = false;
_state = STATE_HEADER;
_status = 0;
@ -159,8 +158,6 @@ 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
@ -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.
*/
@ -289,7 +284,6 @@ public class Ajp13Generator extends AbstractGenerator
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if (!_endp.isOpen())
{
_state = STATE_END;
@ -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,7 +330,6 @@ public class Ajp13Generator extends AbstractGenerator
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if (!_endp.isOpen())
{
_state = STATE_END;
@ -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);
@ -467,7 +458,6 @@ public class Ajp13Generator extends AbstractGenerator
_buffer = tmpbuf;
}
_state = STATE_CONTENT;
}
@ -530,7 +520,6 @@ public class Ajp13Generator extends AbstractGenerator
int len = -1;
int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
switch (to_flush)
{
case 7:
@ -592,8 +581,6 @@ public class Ajp13Generator extends AbstractGenerator
}
// Are we completely finished for now?
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
{
@ -806,9 +793,8 @@ public class Ajp13Generator extends AbstractGenerator
/* ------------------------------------------------------------ */
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
{
@ -838,6 +823,4 @@ public class Ajp13Generator extends AbstractGenerator
}
}

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

@ -277,6 +277,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
{
long filled = _parser.parseAvailable();
io += filled;
if (_parser.isIdle() && _endp.isInputShutdown())
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)
@ -433,7 +454,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
_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: ";

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,17 +149,13 @@ 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
*/
@ -188,7 +191,10 @@ public class HttpExchange
boolean set = false;
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;
}
@ -206,6 +212,9 @@ public class HttpExchange
case STATUS_EXCEPTED:
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
case STATUS_WAITING_FOR_CONNECTION:
@ -217,8 +226,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -231,8 +239,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -248,8 +255,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -262,8 +268,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -279,8 +284,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@ -296,8 +300,7 @@ public class HttpExchange
set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
if (set=_status.compareAndSet(oldStatus,newStatus))
getEventListener().onExpire();
set = setStatusExpired(newStatus,oldStatus);
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)
@ -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,7 +444,8 @@ 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)
{
@ -440,7 +453,8 @@ 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(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)
{
@ -530,7 +547,8 @@ public class HttpExchange
/**
* Set the request URI
*
* @param uri new request URI
* @param uri
* new request URI
* @see #setRequestURI(String)
* @deprecated
*/
@ -544,7 +562,8 @@ public class HttpExchange
* Set the request URI
*
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority<br/>
* where:<br/><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/>
@ -553,7 +572,8 @@ public class HttpExchange
* <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)
{
@ -562,7 +582,8 @@ public class HttpExchange
/* ------------------------------------------------------------ */
/**
* @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)
{
@ -572,6 +593,8 @@ public class HttpExchange
if (uri.isOpaque())
throw new IllegalArgumentException("Opaque URI: " + uri);
LOG.debug("URI = {}",uri.toASCIIString());
String scheme = uri.getScheme();
int port = uri.getPort();
if (port <= 0)
@ -587,8 +610,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(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,8 +636,11 @@ 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)
{
@ -617,8 +649,11 @@ 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(Buffer name, Buffer value)
{
@ -626,7 +661,8 @@ public class HttpExchange
}
/**
* @param value the content type of the request
* @param value
* the content type of the request
*/
public void setRequestContentType(String 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()
{
@ -791,19 +827,44 @@ public class HttpExchange
String state;
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;
}
@ -814,8 +875,10 @@ public class HttpExchange
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)
{

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,9 +91,10 @@ 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);
@ -114,6 +117,8 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
}
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$
*/
@ -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();
_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);
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 int _maxConnectionsPerAddress = 2;
protected String _scheme = "http";
protected Server _server;
protected int _port;
protected HttpClient _httpClient;
protected Connector _connector;
protected AtomicInteger _count = new AtomicInteger();
protected static URI getBaseURI()
{
return URI.create(_scheme + "://localhost:" + _port + "/");
}
/* ------------------------------------------------------------ */
// TODO work out why BeforeClass does not work here?
@Before
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,6 +105,8 @@ public class HttpExchangeTest
{
sender(1,false);
sender(1,true);
sender(10,false);
sender(10,true);
if (Stress.isEnabled())
{
@ -118,11 +115,6 @@ public class HttpExchangeTest
sender(10000,false);
sender(10000,true);
}
else
{
sender(10,false);
sender(10,true);
}
}
/* ------------------------------------------------------------ */
@ -135,7 +127,7 @@ public class HttpExchangeTest
{
_count.set(0);
final CountDownLatch complete = new CountDownLatch(nb);
final CountDownLatch latch=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++)
@ -151,6 +143,8 @@ public class HttpExchangeTest
@Override
protected void onRequestCommitted()
{
if (verbose)
System.err.println("[ ");
result = "committed";
}
@ -158,6 +152,8 @@ public class HttpExchangeTest
@Override
protected void onRequestComplete() throws IOException
{
if (verbose)
System.err.println("[ ==");
result = "sent";
}
@ -165,6 +161,8 @@ public class HttpExchangeTest
/* ------------------------------------------------------------ */
protected void onResponseStatus(Buffer version, int status, Buffer reason)
{
if (verbose)
System.err.println("] "+version+" "+status+" "+reason);
result = "status";
}
@ -172,12 +170,16 @@ public class HttpExchangeTest
@Override
protected void onResponseHeader(Buffer name, Buffer value)
{
if (verbose)
System.err.println("] "+name+": "+value);
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseHeaderComplete() throws IOException
{
if (verbose)
System.err.println("] -");
result = "content";
super.onResponseHeaderComplete();
}
@ -187,19 +189,21 @@ public class HttpExchangeTest
protected void onResponseContent(Buffer content)
{
len += content.length();
if (verbose)
System.err.println("] "+content.length()+" -> "+len);
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseComplete()
{
if (verbose)
System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
result = "complete";
if (len == 2009)
latch.countDown();
allcontent.decrementAndGet();
else
{
System.err.println(n+" ONLY "+len);
}
System.err.println(n + " ONLY " + len+ "/2009");
complete.countDown();
}
@ -207,6 +211,8 @@ 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);
@ -217,6 +223,8 @@ 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);
@ -227,6 +235,8 @@ public class HttpExchangeTest
@Override
protected void onExpire()
{
if (verbose)
System.err.println("] expired");
complete.countDown();
result = "expired";
System.err.println(n + " EXPIRED " + len);
@ -237,11 +247,11 @@ 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");
@ -249,17 +259,12 @@ public class HttpExchangeTest
_httpClient.send(httpExchange[n]);
}
assertTrue(complete.await(45,TimeUnit.SECONDS));
if (!complete.await(2,TimeUnit.SECONDS))
System.err.println(_httpClient.dump());
long elapsed=System.currentTimeMillis()-start;
assertTrue(complete.await(20,TimeUnit.SECONDS));
// make windows-friendly ... System.currentTimeMillis() on windows is dope!
/*
if(elapsed>0)
System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
*/
assertEquals("nb="+nb+" close="+close,0,latch.getCount());
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";
@ -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,6 +569,7 @@ public class HttpExchangeTest
@Test
public void testReserveConnections () throws Exception
{
_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++)
@ -522,7 +577,7 @@ public class HttpExchangeTest
connections[i] = destination.reserveConnection(200);
assertNotNull(connections[i]);
HttpExchange ex = new ContentExchange();
ex.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
ex.setURI(getBaseURI().resolve("?i=" + i));
ex.setMethod(HttpMethods.GET);
connections[i].send(ex);
}
@ -538,13 +593,18 @@ public class HttpExchangeTest
// 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"));
}
/* ------------------------------------------------------------ */
@ -590,99 +649,4 @@ public class HttpExchangeTest
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()
@ -23,8 +33,59 @@ public class SocketConnectionTest extends AbstractConnectionTest
}
@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,65 +13,34 @@
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();
}
/* ------------------------------------------------------------ */
@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;
_server = serverAndClientCreator.createServer();
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
Connector[] connectors = _server.getConnectors();
_port = connectors[0].getLocalPort();
}
/* ------------------------------------------------------------ */

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

@ -22,7 +22,7 @@
</Set>
<Call name="setContextAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
<Arg>.*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$</Arg>
</Call>

View File

@ -158,147 +158,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>
</artifactItems>
</configuration>
</execution>
<execution>
<id>copy</id>
<phase>generate-resources</phase>
@ -317,187 +176,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>
@ -518,45 +196,77 @@
<outputDirectory>${assembly-directory}</outputDirectory>
<destFileName>start.jar</destFileName>
</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>
<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-jsp-2.1</artifactId>
<version>${project.version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<includes>**</includes>
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>org.glassfish.web</groupId>
<artifactId>jsp-impl</artifactId>
<version>${central-jsp-version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<includes>**</includes>
<outputDirectory>${assembly-directory}/lib/jsp</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>
@ -658,6 +368,16 @@
<artifactId>jetty-policy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-monitor</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-websocket</artifactId>
@ -678,5 +398,12 @@
<artifactId>jsp-impl</artifactId>
<version>${central-jsp-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

@ -13,6 +13,7 @@
package org.eclipse.jetty.http;
import java.io.EOFException;
import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
@ -266,9 +267,19 @@ public class HttpParser implements Parser
// Fill buffer if we can
if (length == 0)
{
long filled=fill();
long filled=-1;
IOException ex=null;
try
{
filled=fill();
}
catch(IOException e)
{
LOG.debug(this.toString(),e);
ex=e;
}
if (filled < 0)
if (filled < 0 || _endp.isInputShutdown())
{
if (_headResponse && _state>STATE_END)
{
@ -291,6 +302,12 @@ public class HttpParser implements Parser
return 1;
}
if (ex!=null)
throw ex;
if (!isComplete() && !isIdle())
throw new EOFException();
return -1;
}
length=_buffer.length();

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

@ -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;
@ -78,14 +79,14 @@ public class SocketEndPoint extends StreamEndPoint
@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();
}
/* ------------------------------------------------------------ */
@ -95,9 +96,13 @@ public class SocketEndPoint extends StreamEndPoint
@Override
public void shutdownOutput() throws IOException
{
if (!_socket.isClosed() && !_socket.isOutputShutdown())
if (!isOutputShutdown())
{
super.shutdownOutput();
if (!(_socket instanceof SSLSocket))
_socket.shutdownOutput();
}
}
/* ------------------------------------------------------------ */
@ -107,9 +112,13 @@ public class SocketEndPoint extends StreamEndPoint
@Override
public void shutdownInput() throws IOException
{
if (!_socket.isClosed() && !_socket.isInputShutdown())
if (!isInputShutdown())
{
super.shutdownInput();
if (!(_socket instanceof SSLSocket))
_socket.shutdownInput();
}
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)

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;
/**
*
@ -76,20 +72,30 @@ 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;
}
/*
@ -107,6 +113,7 @@ public class StreamEndPoint implements EndPoint
protected void idleExpired() throws IOException
{
if (_in!=null)
_in.close();
}
@ -115,7 +122,6 @@ public class StreamEndPoint implements EndPoint
*/
public int fill(Buffer buffer) throws IOException
{
// TODO handle null array()
if (_in==null)
return 0;
@ -129,7 +135,15 @@ public class StreamEndPoint implements EndPoint
try
{
return buffer.readFrom(_in,space);
int read=buffer.readFrom(_in, space);
if (read<0 && isOpen())
{
if (!isInputShutdown())
shutdownInput();
else if (isOutputShutdown())
close();
}
return read;
}
catch(SocketTimeoutException e)
{
@ -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();

View File

@ -109,8 +109,11 @@ public class ChannelEndPoint implements EndPoint
if (_channel.isOpen() && _channel instanceof SocketChannel)
{
Socket socket= ((SocketChannel)_channel).socket();
if (!socket.isClosed()&&!socket.isInputShutdown())
if (!socket.isClosed())
{
if(socket.isOutputShutdown())
socket.close();
else if (!socket.isInputShutdown())
socket.shutdownInput();
}
}
@ -124,8 +127,11 @@ public class ChannelEndPoint implements EndPoint
if (_channel.isOpen() && _channel instanceof SocketChannel)
{
Socket socket= ((SocketChannel)_channel).socket();
if (!socket.isClosed()&&!socket.isOutputShutdown())
if (!socket.isClosed())
{
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())
{
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,25 +34,46 @@ 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;
/** 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;
/* ------------------------------------------------------------ */
@ -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)
@ -415,9 +446,19 @@ 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

@ -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,19 +48,14 @@ 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;
@ -390,18 +384,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
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>();
@ -416,9 +402,7 @@ 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;
}
/* ------------------------------------------------------------ */
@ -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;
@ -525,6 +512,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
try
{
if (ch!=null)
ch.close();
}
catch(IOException e2)
@ -537,7 +525,6 @@ 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();
@ -571,12 +558,36 @@ 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());
}
});
}
}
}
}
}
@ -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)
@ -722,126 +743,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
}
/* ------------------------------------------------------------ */
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()
@ -944,6 +845,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/* ------------------------------------------------------------ */
public void destroyEndPoint(SelectChannelEndPoint endp)
{
LOG.debug("destroyEndPoint {}",endp);
_endPoints.remove(endp);
endPointClosed(endp);
}
@ -1037,12 +939,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
Selector selector=_selector;
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 Runnable(){
addChange(new ChangeTask()
{
public void run()
{
dumpKeyState(dump);
@ -1060,6 +965,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
AggregateLifeCycle.dump(out,indent,dump);
}
}
/* ------------------------------------------------------------ */
public void dumpKeyState(List<Object> dumpto)

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,16 +51,7 @@ 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
{
@ -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 ()
{
}
/*------------------------------------------------*/
@ -313,6 +165,22 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
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;
}
/*------------------------------------------------*/
/**
@ -436,8 +304,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
throw ne;
}
Name cname = toCanonicalName (name);
if (cname == null)
@ -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
@ -1155,7 +1020,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
}
}
/*------------------------------------------------*/
@ -1248,8 +1112,6 @@ 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,6 +39,66 @@ 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
{
@ -38,6 +106,85 @@ public class TestLocalJNDI
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

@ -13,6 +13,54 @@
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.glassfish.web</groupId>
<artifactId>jsp-impl</artifactId>
<version>2.1.3-b10</version>
<type>jar</type>
<classifier>sources</classifier>
<overWrite>true</overWrite>
<outputDirectory>target/generated-sources</outputDirectory>
<includes>**/JDTJavaCompiler.java</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
@ -27,13 +75,11 @@
<configuration>
<instructions>
<Import-Package>
com.sun.org.apache.commons.logging;version="[2.1,3)";glassfish="split",
org.apache.jasper;version="[2.1,3)";glassfish="split",
*
</Import-Package>
<Export-Package>org.eclipse.jetty*;version="${parsedVersion.osgiVersion}"</Export-Package>
<Export-Package>org.apache.jasper*;version="${parsedVersion.osgiVersion}"</Export-Package>
<Fragment-Host>org.apache.jasper.glassfish</Fragment-Host>
<!-- disable the uses directive: we don't want to fore eeryone that uses us to
have to depend on com.sun.org.apache.commons.logging provided by jasper-glassfish. -->
<_nouses>true</_nouses>
</instructions>
</configuration>
@ -61,20 +107,10 @@
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-2.1-glassfish</artifactId>
<version>${javax-servlet-jsp-version}</version>
<groupId>org.glassfish.web</groupId>
<artifactId>jsp-impl</artifactId>
<version>2.1.3-b10</version>
<exclusions>
<exclusion>
<groupId>org.mortbay.jetty</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
@ -83,5 +119,11 @@
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>3.7</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,102 +0,0 @@
package org.eclipse.jetty.jsp;
import com.sun.org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* @version $Revision$ $Date$
*/
public class JettyLog implements com.sun.org.apache.commons.logging.Log
{
private static volatile boolean __initialized;
/**
* Called via reflection from WebXmlProcessor
*/
public static synchronized void init()
{
if (!__initialized)
{
__initialized = true;
LogFactory.setLogImplClassName(JettyLog.class.getName());
}
}
private final Logger _logger;
public JettyLog(String name)
{
_logger = Log.getLogger(name);
}
public void fatal(Object o)
{
error(o);
}
public void fatal(Object o, Throwable throwable)
{
error(o, throwable);
}
public boolean isErrorEnabled()
{
return true;
}
public void error(Object o)
{
warn(o);
}
public void error(Object o, Throwable throwable)
{
_logger.warn(String.valueOf(o), throwable);
}
public boolean isWarnEnabled()
{
return true;
}
public void warn(Object o)
{
_logger.warn(String.valueOf(o));
}
public boolean isInfoEnabled()
{
return true;
}
public void info(Object o)
{
_logger.info(String.valueOf(o));
}
public boolean isDebugEnabled()
{
return _logger.isDebugEnabled();
}
public void debug(Object o)
{
_logger.debug(String.valueOf(o));
}
public void debug(Object o, Throwable throwable)
{
_logger.debug(String.valueOf(o), throwable);
}
public boolean isTraceEnabled()
{
return isDebugEnabled();
}
public void trace(Object o)
{
debug(o);
}
}

View File

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

View File

@ -13,14 +13,10 @@
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
@ -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,21 +85,23 @@ 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);
if (_content.length() == 0)
@ -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();
int len = _buffer==null?0:_endp.flush(_buffer);
len =_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

@ -36,6 +36,7 @@ public class FragmentActivator implements BundleActivator
*
*/
public void start(BundleContext context) throws Exception {
System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
}

View File

@ -3,7 +3,7 @@
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-project</artifactId>
<!--version>7.5.0.v20110901</version-->
<version>7.5.1-SNAPSHOT</version>
<version>7.5.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -12,6 +12,7 @@
<name>Jetty :: OSGi :: Servletbridge</name>
<description>Jetty OSGi Servletbridge webapp</description>
<packaging>war</packaging>
<properties><eclipse.pde>false</eclipse.pde></properties>
<dependencies>
<dependency>
<groupId>org.eclipse.equinox</groupId>
@ -38,4 +39,15 @@
<url>http://intalio.org/public/maven2</url>
</repository>
</repositories>
<build>
<plugins><plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<pde>false</pde>
</configuration>
</plugin></plugins>
</build>
</project>

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

@ -50,6 +50,44 @@ public class FrameworkLauncherExtended extends FrameworkLauncher
private boolean deployedInPlace = false;
private URL resourceBaseAsURL = null;
protected static Boolean ASYNCH_START_IN_PROGRESS;
protected static Throwable ASYNCH_START_FAILURE = null;
/**
* If the start is asynch we do it in a different thread and return immediately.
*/
@Override
public synchronized void start() {
if (ASYNCH_START_IN_PROGRESS == null && "true".equals(super.config.getInitParameter("asyncStart"))) {
final ClassLoader webappCl = Thread.currentThread().getContextClassLoader();
Thread th = new Thread() {
public void run() {
Thread.currentThread().setContextClassLoader(webappCl);
System.out.println("Jetty-Nested: Starting equinox asynchroneously.");
FrameworkLauncherExtended.this.start();
System.out.println("Jetty-Nested: Finished starting equinox asynchroneously.");
}
};
ASYNCH_START_IN_PROGRESS = true;
try {
th.start();
} catch (Throwable t) {
ASYNCH_START_FAILURE = t;
if (t instanceof RuntimeException) {
throw (RuntimeException)t;
} else {
throw new RuntimeException("Equinox failed to start", t);
}
} finally {
ASYNCH_START_IN_PROGRESS = false;
}
} else {
System.out.println("Jetty-Nested: Starting equinox synchroneously.");
super.start();
System.out.println("Jetty-Nested: Finished starting equinox synchroneously.");
}
}
/**
* try to find the resource base for this webapp by looking for the launcher initialization file.
*/
@ -248,7 +286,10 @@ public class FrameworkLauncherExtended extends FrameworkLauncher
String logback = System.getProperty("logback.configurationFile");
if (logback == null)
{
File etcLogback = new File(jettyHome,"etc/logback.xml");
File etcLogback = new File(jettyHome,"etc/logback-nested.xml");
if (!etcLogback.exists()) {
etcLogback = new File(jettyHome,"etc/logback.xml");
}
if (etcLogback.exists())
{
System.setProperty("logback.configurationFile",etcLogback.getAbsolutePath());

View File

@ -5,13 +5,19 @@
<servlet-name>proxy</servlet-name>
<display-name>Transparent Proxy Servlet and Equinox Framework Controller</display-name>
<description>Transparent Proxy Servlet and Equinox Framework Controller</description>
<servlet-class>org.eclipse.equinox.servletbridge.BridgeServlet</servlet-class>
<servlet-class>org.eclipse.jetty.osgi.servletbridge.BridgeServletExtended</servlet-class>
<!-- Point to a folder where an equinox installation exists.
When this parameter is defined, that equinox installation is launched in place.
The parameter can also be passed as a system property. -->
<init-param>
<param-name>osgi.install.area</param-name>
<param-value>/WEB-INF/eclipse</param-value>
</init-param>
<!-- Start equinox in a different thread and display a simple
a simple status message until it is started. -->
<init-param>
<param-name>asyncStart</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>commandline</param-name>

View File

@ -13,19 +13,20 @@
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;
@ -36,123 +37,90 @@ import org.eclipse.jetty.util.log.Logger;
*/
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"));
setupPropertyUserStore(options);
}
public void loadProperties (String filename)
private void setupPropertyUserStore(Map<String, ?> options)
{
File propsFile;
if (filename == null)
if (_propertyUserStores.get(_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");
}
parseConfig(options);
PropertyUserStore _propertyUserStore = new PropertyUserStore();
_propertyUserStore.setConfig(_filename);
_propertyUserStore.setRefreshInterval(_refreshInterval);
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
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);
_propertyUserStore.start();
}
catch (Exception e)
{
LOG.warn("Error loading properties from file", e);
throw new RuntimeException(e);
LOG.warn("Exception while starting propertyUserStore: ",e);
}
_propertyUserStores.put(_filename,_propertyUserStore);
}
}
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
* 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,6 +74,11 @@
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</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

@ -19,7 +19,6 @@ 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;
@ -46,6 +45,7 @@ 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>
@ -68,6 +68,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
* &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;

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;
@ -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)
{
@ -134,47 +121,9 @@ public class HashLoginService extends MappedLoginService
@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();
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
}
if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
{
String[] roleArray = IdentityService.NO_ROLES;
if (roles != null && roles.length() > 0)
roleArray = roles.split(",");
known.add(username);
putUser(username,Credential.getCredential(credentials),roleArray);
}
}
Iterator<String> users = _users.keySet().iterator();
while(users.hasNext())
{
String user=users.next();
if (!known.contains(user))
users.remove();
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
@ -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;
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
}
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();
_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;
/* ------------------------------------------------------------ */
@ -58,6 +67,12 @@ public class PropertyUserStore extends AbstractLifeCycle
_config = config;
}
/* ------------------------------------------------------------ */
public UserIdentity getUserIdentity(String userName)
{
return _knownUserIdentities.get(userName);
}
/* ------------------------------------------------------------ */
/**
* returns the resource associated with the configured properties file, creating it if necessary
@ -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,14 +237,16 @@ 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)
{
Resource r = Resource.newResource(filenames.get(0));
if (r.getFile().equals(_configResource.getFile()))
loadUsers();
}
}

View File

@ -66,7 +66,13 @@ public class BasicAuthenticator extends LoginAuthenticator
if (credentials != null)
{
credentials = credentials.substring(credentials.indexOf(' ')+1);
int space=credentials.indexOf(' ');
if (space>0)
{
String method=credentials.substring(0,space);
if ("basic".equalsIgnoreCase(method))
{
credentials = credentials.substring(space+1);
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
int i = credentials.indexOf(':');
if (i>0)
@ -82,6 +88,8 @@ public class BasicAuthenticator extends LoginAuthenticator
}
}
}
}
}
if (_deferred.isDeferred(response))
return Authentication.UNAUTHENTICATED;

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,86 +207,58 @@ public class DigestAuthenticator extends LoginAuthenticator
}
/* ------------------------------------------------------------ */
public String newNonce(Request request)
{
long ts=request.getTimeStamp();
long sk = _nonceSecret;
Nonce nonce;
do
{
byte[] nounce = new byte[24];
for (int i = 0; i < 8; i++)
{
nounce[i] = (byte) (ts & 0xff);
ts = ts >> 8;
nounce[8 + i] = (byte) (sk & 0xff);
sk = sk >> 8;
}
_random.nextBytes(nounce);
byte[] hash = null;
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(nounce, 0, 16);
hash = md.digest();
}
catch (Exception e)
{
LOG.warn(e);
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
}
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
_nonceQueue.add(nonce);
for (int i = 0; i < hash.length; i++)
{
nounce[8 + i] = hash[i];
if (i == 23) break;
}
return new String(B64Code.encode(nounce));
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;
nonce = _nonceCount.get(digest.nonce);
if (nonce==null)
return 0;
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
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;
}
@ -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

@ -107,5 +107,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();
// 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

@ -222,6 +222,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();
@ -233,6 +234,7 @@ public class Dispatcher implements RequestDispatcher
try
{
baseRequest.setHandled(false);
baseRequest.setDispatcherType(dispatch);
if (_named!=null)
@ -279,6 +281,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);
@ -303,6 +307,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;
}
@ -453,29 +453,29 @@ public abstract class HttpConnection extends AbstractConnection
catch (EofException e)
{
LOG.debug(e);
_request.setHandled(true);
error=true;
_request.setHandled(true);
}
catch (RuntimeIOException 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)
{
if (e instanceof ThreadDeath)
throw (ThreadDeath)e;
error=true;
LOG.warn(String.valueOf(_uri),e);
error=true;
_request.setHandled(true);
_generator.sendError(info==null?400:500, null, null, true);
}
@ -509,7 +509,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())
@ -671,6 +676,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();
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@ -960,8 +975,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,8 +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;
private boolean _closed;
// These are held here for reuse by Writer
@ -46,12 +46,17 @@ public class HttpOutput extends ServletOutputStream
char[] _chars;
ByteArrayOutputStream2 _bytes;
/* ------------------------------------------------------------ */
public HttpOutput(HttpConnection connection)
{
_connection=connection;
_generator=(AbstractGenerator)connection.getGenerator();
}
/* ------------------------------------------------------------ */
public HttpOutput(AbstractGenerator generator, long maxIdleTime)
public int getMaxIdleTime()
{
_generator=generator;
_maxIdleTime=maxIdleTime;
return _connection.getMaxIdleTime();
}
/* ------------------------------------------------------------ */
@ -86,7 +91,7 @@ public class HttpOutput extends ServletOutputStream
@Override
public void flush() throws IOException
{
_generator.flush(_maxIdleTime);
_generator.flush(getMaxIdleTime());
}
/* ------------------------------------------------------------ */
@ -121,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())
@ -151,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())
@ -174,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

@ -186,7 +186,7 @@ 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()
{
@ -202,6 +202,8 @@ public class Request implements HttpServletRequest
_paramsExtracted = true;
try
{
// Handle query string
if (_uri!=null && _uri.hasQuery())
{
@ -285,6 +287,13 @@ public class Request implements HttpServletRequest
}
}
}
finally
{
//ensure params always set (even if empty) after extraction
if (_parameters==null)
_parameters=_baseParameters;
}
}
/* ------------------------------------------------------------ */
public AsyncContext getAsyncContext()

View File

@ -430,7 +430,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;
@ -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);

View File

@ -801,7 +801,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,6 +476,10 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
InitialContext ic = new InitialContext();
_datasource = (DataSource)ic.lookup(_jndiName);
}
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;
/* ------------------------------------------------------------ */
/**
@ -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();
}
customizeEngine(engine);
return engine;
engine = _sslContextFactory.newSslEngine();
}
/* ------------------------------------------------------------ */
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

@ -14,22 +14,20 @@
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;
@ -67,6 +65,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
}
/* ------------------------------------------------------------ */
public SslSocketConnector(SslContextFactory sslContextFactory)
{
_sslContextFactory = sslContextFactory;
@ -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,11 +351,7 @@ 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();
@ -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);
}
/* ------------------------------------------------------------ */

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

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