The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
*
*
- *
The HttpExchange class is intended to be used by a developer wishing to have close asynchronous
- * interaction with the the exchange.
- * Typically a developer will extend the HttpExchange class with a derived
- * class that overrides some or all of the onXxx callbacks.
- * 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}.
+ *
+ * The HttpExchange class is intended to be used by a developer wishing to have close asynchronous interaction with the the exchange.
+ * Typically a developer will extend the HttpExchange class with a derived class that overrides some or all of the onXxx callbacks.
+ * 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}.
+ *
*
- *
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).
+ *
+ * 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).
+ *
*
- *
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.
+ *
+ * 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.
+ *
*/
public class HttpExchange
{
@@ -106,9 +110,10 @@ public class HttpExchange
// a timeout for this exchange
private long _timeout = -1;
private volatile Timeout.Task _timeoutTask;
-
- private long _lastStateChange=-1;
+ private long _lastStateChange=System.currentTimeMillis();
private long _sent=-1;
+ private int _lastState=-1;
+ private int _lastStatePeriod=-1;
boolean _onRequestCompleteDone;
boolean _onResponseCompleteDone;
@@ -131,8 +136,10 @@ public class HttpExchange
}
/**
- * @param status the status to wait for
- * @throws InterruptedException if the waiting thread is interrupted
+ * @param status
+ * the status to wait for
+ * @throws InterruptedException
+ * if the waiting thread is interrupted
* @deprecated Use {@link #waitForDone()} instead
*/
@Deprecated
@@ -142,21 +149,17 @@ public class HttpExchange
}
/**
- * Wait until the exchange is "done".
- * Done is defined as when a final state has been passed to the
- * HttpExchange via the associated onXxx call. Note that an
- * exchange can transit a final state when being used as part
- * of a dialog (eg {@link SecurityListener}. Done status
- * is thus defined as:
- * 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:
+ *
+ *
+ *
* @return the done status
* @throws InterruptedException
*/
- public int waitForDone () throws InterruptedException
+ public int waitForDone() throws InterruptedException
{
synchronized (this)
{
@@ -170,12 +173,12 @@ public class HttpExchange
{
// TODO - this should do a cancel and wakeup everybody that was waiting.
// might need a version number concept
- synchronized(this)
+ synchronized (this)
{
- _timeoutTask=null;
- _onRequestCompleteDone=false;
- _onResponseCompleteDone=false;
- _onDone=false;
+ _timeoutTask = null;
+ _onRequestCompleteDone = false;
+ _onResponseCompleteDone = false;
+ _onDone = false;
setStatus(STATUS_START);
}
}
@@ -186,13 +189,16 @@ public class HttpExchange
{
int oldStatus = _status.get();
boolean set = false;
- if (oldStatus!=newStatus)
+ if (oldStatus != newStatus)
{
- _lastStateChange=System.currentTimeMillis();
+ long now = System.currentTimeMillis();
+ _lastStatePeriod=(int)(now-_lastStateChange);
+ _lastState=oldStatus;
+ _lastStateChange=now;
if (newStatus==STATUS_SENDING_REQUEST)
_sent=_lastStateChange;
}
-
+
// State machine: from which old status you can go into which new status
switch (oldStatus)
{
@@ -204,7 +210,10 @@ public class HttpExchange
case STATUS_WAITING_FOR_COMMIT:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
+ break;
+ case STATUS_EXPIRED:
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -214,11 +223,10 @@ public class HttpExchange
case STATUS_WAITING_FOR_COMMIT:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -228,11 +236,10 @@ public class HttpExchange
case STATUS_SENDING_REQUEST:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -240,16 +247,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_WAITING_FOR_RESPONSE:
- if (set=_status.compareAndSet(oldStatus,newStatus))
+ if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onRequestCommitted();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -259,11 +265,10 @@ public class HttpExchange
case STATUS_PARSING_HEADERS:
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -271,16 +276,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_PARSING_CONTENT:
- if (set=_status.compareAndSet(oldStatus,newStatus))
+ if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onResponseHeaderComplete();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -288,16 +292,15 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_COMPLETED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
+ if (set = _status.compareAndSet(oldStatus,newStatus))
getEventListener().onResponseComplete();
break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_EXPIRED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
- getEventListener().onExpire();
+ set = setStatusExpired(newStatus,oldStatus);
break;
}
break;
@@ -307,12 +310,12 @@ public class HttpExchange
case STATUS_START:
case STATUS_EXCEPTED:
case STATUS_WAITING_FOR_RESPONSE:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
case STATUS_CANCELLING:
case STATUS_EXPIRED:
// Don't change the status, it's too late
- set=true;
+ set = true;
break;
}
break;
@@ -321,12 +324,12 @@ public class HttpExchange
{
case STATUS_EXCEPTED:
case STATUS_CANCELLED:
- if (set=_status.compareAndSet(oldStatus,newStatus))
+ if (set = _status.compareAndSet(oldStatus,newStatus))
done();
break;
default:
// Ignore other statuses, we're cancelling
- set=true;
+ set = true;
break;
}
break;
@@ -336,10 +339,10 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_START:
- set=_status.compareAndSet(oldStatus,newStatus);
+ set = _status.compareAndSet(oldStatus,newStatus);
break;
default:
- set=true;
+ set = true;
break;
}
break;
@@ -357,6 +360,14 @@ public class HttpExchange
}
}
+ private boolean setStatusExpired(int newStatus, int oldStatus)
+ {
+ boolean set;
+ if (set = _status.compareAndSet(oldStatus,newStatus))
+ getEventListener().onExpire();
+ return set;
+ }
+
public boolean isDone()
{
synchronized (this)
@@ -369,7 +380,7 @@ public class HttpExchange
* @deprecated
*/
@Deprecated
- public boolean isDone (int status)
+ public boolean isDone(int status)
{
return isDone();
}
@@ -381,10 +392,10 @@ public class HttpExchange
public void setEventListener(HttpEventListener listener)
{
- _listener=listener;
+ _listener = listener;
}
- public void setTimeout( long timeout )
+ public void setTimeout(long timeout)
{
_timeout = timeout;
}
@@ -395,7 +406,8 @@ public class HttpExchange
}
/**
- * @param url an absolute URL (for example 'http://localhost/foo/bar?a=1')
+ * @param url
+ * an absolute URL (for example 'http://localhost/foo/bar?a=1')
*/
public void setURL(String url)
{
@@ -403,7 +415,8 @@ public class HttpExchange
}
/**
- * @param address the address of the server
+ * @param address
+ * the address of the server
*/
public void setAddress(Address address)
{
@@ -421,8 +434,7 @@ public class HttpExchange
/**
* the local address used by the connection
*
- * Note: this method will not be populated unless the exchange
- * has been executed by the HttpClient
+ * Note: this method will not be populated unless the exchange has been executed by the HttpClient
*
* @return the local address used for the running of the exchange if available, null otherwise.
*/
@@ -432,15 +444,17 @@ public class HttpExchange
}
/**
- * @param scheme the scheme of the URL (for example 'http')
+ * @param scheme
+ * the scheme of the URL (for example 'http')
*/
public void setScheme(Buffer scheme)
{
_scheme = scheme;
}
-
+
/**
- * @param scheme the scheme of the URL (for example 'http')
+ * @param scheme
+ * the scheme of the URL (for example 'http')
*/
public void setScheme(String scheme)
{
@@ -464,7 +478,8 @@ public class HttpExchange
}
/**
- * @param version the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
+ * @param version
+ * the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
*/
public void setVersion(int version)
{
@@ -472,7 +487,8 @@ public class HttpExchange
}
/**
- * @param version the HTTP protocol version as string
+ * @param version
+ * the HTTP protocol version as string
*/
public void setVersion(String version)
{
@@ -493,7 +509,8 @@ public class HttpExchange
}
/**
- * @param method the HTTP method (for example 'GET')
+ * @param method
+ * the HTTP method (for example 'GET')
*/
public void setMethod(String method)
{
@@ -528,9 +545,10 @@ public class HttpExchange
}
/**
- * Set the request URI
+ * Set the request URI
*
- * @param uri new request URI
+ * @param uri
+ * new request URI
* @see #setRequestURI(String)
* @deprecated
*/
@@ -541,36 +559,41 @@ public class HttpExchange
}
/**
- * Set the request URI
+ * Set the request URI
*
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority
- * where:
- * "*" - request applies to server itself
+ * where:
+ *
+ * "*" - request applies to server itself
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context
- * (this form is generated automatically by HttpClient)
- * abs_path - used for most methods, e.g. /context
- * authority - used for CONNECT method only, e.g. localhost:8080
+ * (this form is generated automatically by HttpClient)
+ * abs_path - used for most methods, e.g. /context
+ * authority - used for CONNECT method only, e.g. localhost:8080
*
* For complete definition of URI components, see RFC 2396 sec3.
- *
- * @param uri new request URI
+ *
+ * @param uri
+ * new request URI
*/
public void setRequestURI(String uri)
{
_uri = uri;
}
-
+
/* ------------------------------------------------------------ */
/**
- * @param uri an absolute URI (for example 'http://localhost/foo/bar?a=1')
+ * @param uri
+ * an absolute URI (for example 'http://localhost/foo/bar?a=1')
*/
public void setURI(URI uri)
{
if (!uri.isAbsolute())
- throw new IllegalArgumentException("!Absolute URI: "+uri);
-
+ throw new IllegalArgumentException("!Absolute URI: " + uri);
+
if (uri.isOpaque())
- throw new IllegalArgumentException("Opaque URI: "+uri);
+ throw new IllegalArgumentException("Opaque URI: " + uri);
+
+ LOG.debug("URI = {}",uri.toASCIIString());
String scheme = uri.getScheme();
int port = uri.getPort();
@@ -582,13 +605,16 @@ public class HttpExchange
HttpURI httpUri = new HttpURI(uri);
String completePath = httpUri.getCompletePath();
- setRequestURI(completePath==null ? "/" : completePath);
+ setRequestURI(completePath == null?"/":completePath);
}
/**
* Adds the specified request header
- * @param name the header name
- * @param value the header value
+ *
+ * @param name
+ * the header name
+ * @param value
+ * the header value
*/
public void addRequestHeader(String name, String value)
{
@@ -597,8 +623,11 @@ public class HttpExchange
/**
* Adds the specified request header
- * @param name the header name
- * @param value the header value
+ *
+ * @param name
+ * the header name
+ * @param value
+ * the header value
*/
public void addRequestHeader(Buffer name, Buffer value)
{
@@ -607,30 +636,37 @@ public class HttpExchange
/**
* Sets the specified request header
- * @param name the header name
- * @param value the header value
+ *
+ * @param name
+ * the header name
+ * @param value
+ * the header value
*/
public void setRequestHeader(String name, String value)
{
- getRequestFields().put(name, value);
+ getRequestFields().put(name,value);
}
/**
* Sets the specified request header
- * @param name the header name
- * @param value the header value
+ *
+ * @param name
+ * the header name
+ * @param value
+ * the header value
*/
public void setRequestHeader(Buffer name, Buffer value)
{
- getRequestFields().put(name, value);
+ getRequestFields().put(name,value);
}
/**
- * @param value the content type of the request
+ * @param value
+ * the content type of the request
*/
public void setRequestContentType(String value)
{
- getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER, value);
+ getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
}
/**
@@ -642,7 +678,8 @@ public class HttpExchange
}
/**
- * @param requestContent the request content
+ * @param requestContent
+ * the request content
*/
public void setRequestContent(Buffer requestContent)
{
@@ -650,7 +687,8 @@ public class HttpExchange
}
/**
- * @param stream the request content as a stream
+ * @param stream
+ * the request content as a stream
*/
public void setRequestContentSource(InputStream stream)
{
@@ -708,7 +746,8 @@ public class HttpExchange
}
/**
- * @param retryStatus whether a retry will be attempted or not
+ * @param retryStatus
+ * whether a retry will be attempted or not
*/
public void setRetryStatus(boolean retryStatus)
{
@@ -716,13 +755,10 @@ public class HttpExchange
}
/**
- * Initiates the cancelling of this exchange.
- * The status of the exchange is set to {@link #STATUS_CANCELLING}.
- * Cancelling the exchange is an asynchronous operation with respect to the request/response,
- * and as such checking the request/response status of a cancelled exchange may return undefined results
- * (for example it may have only some of the response headers being sent by the server).
- * The cancelling of the exchange is completed when the exchange status (see {@link #getStatus()}) is
- * {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
+ * Initiates the cancelling of this exchange. The status of the exchange is set to {@link #STATUS_CANCELLING}. Cancelling the exchange is an asynchronous
+ * operation with respect to the request/response, and as such checking the request/response status of a cancelled exchange may return undefined results
+ * (for example it may have only some of the response headers being sent by the server). The cancelling of the exchange is completed when the exchange
+ * status (see {@link #getStatus()}) is {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
*/
public void cancel()
{
@@ -732,10 +768,10 @@ public class HttpExchange
private void done()
{
- synchronized(this)
+ synchronized (this)
{
disassociate();
- _onDone=true;
+ _onDone = true;
notifyAll();
}
}
@@ -764,8 +800,8 @@ public class HttpExchange
void associate(HttpConnection connection)
{
- if (connection.getEndPoint().getLocalHost() != null)
- _localAddress = new Address(connection.getEndPoint().getLocalHost(), connection.getEndPoint().getLocalPort());
+ if (connection.getEndPoint().getLocalHost() != null)
+ _localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
_connection = connection;
if (getStatus() == STATUS_CANCELLING)
@@ -789,33 +825,60 @@ public class HttpExchange
public static String toState(int s)
{
String state;
- switch(s)
+ switch (s)
{
- case STATUS_START: state="START"; break;
- case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
- case STATUS_WAITING_FOR_COMMIT: state="CONNECTED"; break;
- case STATUS_SENDING_REQUEST: state="SENDING"; break;
- case STATUS_WAITING_FOR_RESPONSE: state="WAITING"; break;
- case STATUS_PARSING_HEADERS: state="HEADERS"; break;
- case STATUS_PARSING_CONTENT: state="CONTENT"; break;
- case STATUS_COMPLETED: state="COMPLETED"; break;
- case STATUS_EXPIRED: state="EXPIRED"; break;
- case STATUS_EXCEPTED: state="EXCEPTED"; break;
- case STATUS_CANCELLING: state="CANCELLING"; break;
- case STATUS_CANCELLED: state="CANCELLED"; break;
- default: state="UNKNOWN";
+ case STATUS_START:
+ state = "START";
+ break;
+ case STATUS_WAITING_FOR_CONNECTION:
+ state = "CONNECTING";
+ break;
+ case STATUS_WAITING_FOR_COMMIT:
+ state = "CONNECTED";
+ break;
+ case STATUS_SENDING_REQUEST:
+ state = "SENDING";
+ break;
+ case STATUS_WAITING_FOR_RESPONSE:
+ state = "WAITING";
+ break;
+ case STATUS_PARSING_HEADERS:
+ state = "HEADERS";
+ break;
+ case STATUS_PARSING_CONTENT:
+ state = "CONTENT";
+ break;
+ case STATUS_COMPLETED:
+ state = "COMPLETED";
+ break;
+ case STATUS_EXPIRED:
+ state = "EXPIRED";
+ break;
+ case STATUS_EXCEPTED:
+ state = "EXCEPTED";
+ break;
+ case STATUS_CANCELLING:
+ state = "CANCELLING";
+ break;
+ case STATUS_CANCELLED:
+ state = "CANCELLED";
+ break;
+ default:
+ state = "UNKNOWN";
}
return state;
}
-
+
@Override
public String toString()
{
String state=toState(getStatus());
long now=System.currentTimeMillis();
long forMs = now -_lastStateChange;
- String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
- if (getStatus()>=STATUS_SENDING_REQUEST)
+ String s= _lastState>=0
+ ?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs)
+ :String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
+ if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0)
s+="sent="+(now-_sent)+"ms";
return s;
}
@@ -828,79 +891,93 @@ public class HttpExchange
}
/**
- * Callback called when the request headers have been sent to the server.
- * This implementation does nothing.
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when the request headers have been sent to the server. This implementation does nothing.
+ *
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onRequestCommitted() throws IOException
{
}
/**
- * Callback called when the request and its body have been sent to the server.
- * This implementation does nothing.
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when the request and its body have been sent to the server. This implementation does nothing.
+ *
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onRequestComplete() throws IOException
{
}
/**
- * Callback called when a response status line has been received from the server.
- * This implementation does nothing.
- * @param version the HTTP version
- * @param status the HTTP status code
- * @param reason the HTTP status reason string
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when a response status line has been received from the server. This implementation does nothing.
+ *
+ * @param version
+ * the HTTP version
+ * @param status
+ * the HTTP status code
+ * @param reason
+ * the HTTP status reason string
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
{
}
/**
- * Callback called for each response header received from the server.
- * This implementation does nothing.
- * @param name the header name
- * @param value the header value
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called for each response header received from the server. This implementation does nothing.
+ *
+ * @param name
+ * the header name
+ * @param value
+ * the header value
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
{
}
/**
- * Callback called when the response headers have been completely received from the server.
- * This implementation does nothing.
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when the response headers have been completely received from the server. This implementation does nothing.
+ *
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onResponseHeaderComplete() throws IOException
{
}
/**
- * Callback called for each chunk of the response content received from the server.
- * This implementation does nothing.
- * @param content the buffer holding the content chunk
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called for each chunk of the response content received from the server. This implementation does nothing.
+ *
+ * @param content
+ * the buffer holding the content chunk
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onResponseContent(Buffer content) throws IOException
{
}
/**
- * Callback called when the entire response has been received from the server
- * This implementation does nothing.
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when the entire response has been received from the server This implementation does nothing.
+ *
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onResponseComplete() throws IOException
{
}
/**
- * Callback called when an exception was thrown during an attempt to establish the connection
- * with the server (for example the server is not listening).
+ * Callback called when an exception was thrown during an attempt to establish the connection with the server (for example the server is not listening).
* This implementation logs a warning.
- * @param x the exception thrown attempting to establish the connection with the server
+ *
+ * @param x
+ * the exception thrown attempting to establish the connection with the server
*/
protected void onConnectionFailed(Throwable x)
{
@@ -908,9 +985,10 @@ public class HttpExchange
}
/**
- * Callback called when any other exception occurs during the handling of this exchange.
- * This implementation logs a warning.
- * @param x the exception thrown during the handling of this exchange
+ * Callback called when any other exception occurs during the handling of this exchange. This implementation logs a warning.
+ *
+ * @param x
+ * the exception thrown during the handling of this exchange
*/
protected void onException(Throwable x)
{
@@ -918,8 +996,7 @@ public class HttpExchange
}
/**
- * Callback called when no response has been received within the timeout.
- * This implementation logs a warning.
+ * Callback called when no response has been received within the timeout. This implementation logs a warning.
*/
protected void onExpire()
{
@@ -927,9 +1004,10 @@ public class HttpExchange
}
/**
- * Callback called when the request is retried (due to failures or authentication).
- * Implementations must reset any consumable content that needs to be sent.
- * @throws IOException allowed to be thrown by overriding code
+ * Callback called when the request is retried (due to failures or authentication). Implementations must reset any consumable content that needs to be sent.
+ *
+ * @throws IOException
+ * allowed to be thrown by overriding code
*/
protected void onRetry() throws IOException
{
@@ -948,8 +1026,7 @@ public class HttpExchange
}
/**
- * @return true if the exchange should have listeners configured for it by the destination,
- * false if this is being managed elsewhere
+ * @return true if the exchange should have listeners configured for it by the destination, false if this is being managed elsewhere
* @see #setConfigureListeners(boolean)
*/
public boolean configureListeners()
@@ -958,7 +1035,8 @@ public class HttpExchange
}
/**
- * @param autoConfigure whether the listeners are configured by the destination or elsewhere
+ * @param autoConfigure
+ * whether the listeners are configured by the destination or elsewhere
*/
public void setConfigureListeners(boolean autoConfigure)
{
@@ -981,7 +1059,7 @@ public class HttpExchange
HttpClient httpClient = destination.getHttpClient();
long timeout = getTimeout();
if (timeout > 0)
- httpClient.schedule(_timeoutTask, timeout);
+ httpClient.schedule(_timeoutTask,timeout);
else
httpClient.schedule(_timeoutTask);
}
@@ -1045,7 +1123,7 @@ public class HttpExchange
}
finally
{
- synchronized(HttpExchange.this)
+ synchronized (HttpExchange.this)
{
_onRequestCompleteDone = true;
// Member _onDone may already be true, for example
@@ -1066,7 +1144,7 @@ public class HttpExchange
}
finally
{
- synchronized(HttpExchange.this)
+ synchronized (HttpExchange.this)
{
_onResponseCompleteDone = true;
// Member _onDone may already be true, for example
@@ -1101,7 +1179,7 @@ public class HttpExchange
public void onRetry()
{
- HttpExchange.this.setRetryStatus( true );
+ HttpExchange.this.setRetryStatus(true);
try
{
HttpExchange.this.onRetry();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java
index b46d2bcc4fa..00bc4595432 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java
@@ -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 );
+ }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java
index 333c4166ba4..fd37190a2b5 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java
@@ -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 _connectingChannels = new ConcurrentHashMap();
- private SSLContext _sslContext;
private Buffers _sslBuffers;
/**
@@ -89,31 +91,34 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
public void startConnection( HttpDestination destination )
throws IOException
{
+ SocketChannel channel = null;
try
{
- SocketChannel channel = SocketChannel.open();
+ channel = SocketChannel.open();
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
channel.socket().setTcpNoDelay(true);
if (_httpClient.isConnectBlocking())
{
- channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
- channel.configureBlocking(false);
- _selectorManager.register( channel, destination );
+ channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
+ channel.configureBlocking(false);
+ _selectorManager.register( channel, destination );
}
else
{
- channel.configureBlocking( false );
- channel.connect(address.toSocketAddress());
- _selectorManager.register( channel, destination );
- ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
+ channel.configureBlocking(false);
+ channel.connect(address.toSocketAddress());
+ _selectorManager.register(channel,destination);
+ ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
- _connectingChannels.put(channel, connectTimeout);
+ _connectingChannels.put(channel,connectTimeout);
}
}
catch(IOException ex)
{
+ if (channel != null)
+ channel.close();
destination.onConnectionFailed(ex);
}
}
@@ -194,19 +199,16 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
{
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
- if (_sslContext == null)
- _sslContext = sslContextFactory.getSslContext();
-
SSLEngine sslEngine;
- if (channel != null && sslContextFactory.isSessionCachingEnabled())
+ if (channel != null)
{
String peerHost = channel.socket().getInetAddress().getHostAddress();
int peerPort = channel.socket().getPort();
- sslEngine = _sslContext.createSSLEngine(peerHost, peerPort);
+ sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
}
else
{
- sslEngine = _sslContext.createSSLEngine();
+ sslEngine = sslContextFactory.newSslEngine();
}
sslEngine.setUseClientMode(true);
sslEngine.beginHandshake();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SocketConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SocketConnector.java
index 226cd644ffd..031c0cb5bb3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/SocketConnector.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SocketConnector.java
@@ -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);
+ }
+ }
}
});
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java
index 2cd06974593..9f5bbaa95cb 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractConnectionTest.java
@@ -14,9 +14,9 @@
package org.eclipse.jetty.client;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
@@ -25,6 +25,9 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
/**
* @version $Revision$ $Date$
*/
@@ -37,7 +40,7 @@ public abstract class AbstractConnectionTest
// httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
return httpClient;
}
-
+
@Test
public void testServerClosedConnection() throws Exception
{
@@ -57,6 +60,19 @@ public abstract class AbstractConnectionTest
httpClient.send(exchange);
Socket remote = serverSocket.accept();
+
+ // HttpClient.send() above is async, so if we write the response immediately
+ // there is a chance that it arrives before the request is being sent, so we
+ // read the request before sending the response to avoid the race
+ InputStream input = remote.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.length() == 0)
+ break;
+ }
+
OutputStream output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
@@ -80,6 +96,15 @@ public abstract class AbstractConnectionTest
httpClient.send(exchange);
remote = serverSocket.accept();
+
+ input = remote.getInputStream();
+ reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.length() == 0)
+ break;
+ }
+
output = remote.getOutputStream();
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
@@ -94,6 +119,105 @@ public abstract class AbstractConnectionTest
}
}
+ @Test
+ public void testServerClosedIncomplete() throws Exception
+ {
+ ServerSocket serverSocket = new ServerSocket();
+ serverSocket.bind(null);
+ int port=serverSocket.getLocalPort();
+
+ HttpClient httpClient = newHttpClient();
+ httpClient.setMaxConnectionsPerAddress(1);
+ httpClient.start();
+ try
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+ HttpExchange exchange = new ConnectionExchange(latch);
+ exchange.setAddress(new Address("localhost", port));
+ exchange.setRequestURI("/");
+ httpClient.send(exchange);
+
+ Socket remote = serverSocket.accept();
+
+ // HttpClient.send() above is async, so if we write the response immediately
+ // there is a chance that it arrives before the request is being sent, so we
+ // read the request before sending the response to avoid the race
+ InputStream input = remote.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.length() == 0)
+ break;
+ }
+
+ OutputStream output = remote.getOutputStream();
+ output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
+ output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
+ output.write("\r\n".getBytes("UTF-8"));
+ output.flush();
+
+ remote.close();
+
+ assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
+
+ }
+ finally
+ {
+ httpClient.stop();
+ }
+ }
+
+ @Test
+ public void testServerHalfClosedIncomplete() throws Exception
+ {
+ ServerSocket serverSocket = new ServerSocket();
+ serverSocket.bind(null);
+ int port=serverSocket.getLocalPort();
+
+ HttpClient httpClient = newHttpClient();
+ httpClient.setIdleTimeout(10000);
+ httpClient.setMaxConnectionsPerAddress(1);
+ httpClient.start();
+ try
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+ HttpExchange exchange = new ConnectionExchange(latch);
+ exchange.setAddress(new Address("localhost", port));
+ exchange.setRequestURI("/");
+ httpClient.send(exchange);
+
+ Socket remote = serverSocket.accept();
+
+ // HttpClient.send() above is async, so if we write the response immediately
+ // there is a chance that it arrives before the request is being sent, so we
+ // read the request before sending the response to avoid the race
+ InputStream input = remote.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.length() == 0)
+ break;
+ }
+
+ OutputStream output = remote.getOutputStream();
+ output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
+ output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
+ output.write("\r\n".getBytes("UTF-8"));
+ output.flush();
+
+ remote.shutdownOutput();
+
+ assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
+
+ }
+ finally
+ {
+ httpClient.stop();
+ }
+ }
+
@Test
public void testConnectionFailed() throws Exception
{
@@ -262,16 +386,16 @@ public abstract class AbstractConnectionTest
}
}
- private class ConnectionExchange extends HttpExchange
+ protected class ConnectionExchange extends HttpExchange
{
private final CountDownLatch latch;
- private ConnectionExchange()
+ protected ConnectionExchange()
{
this.latch = null;
}
- private ConnectionExchange(CountDownLatch latch)
+ protected ConnectionExchange(CountDownLatch latch)
{
this.latch = latch;
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java
index cb5812780a2..c1d5c3da2c1 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java
@@ -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;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java
index 75dc89a1ed3..7dbbefd7e5b 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSelectConnectionTest.java
@@ -22,4 +22,12 @@ public class AsyncSelectConnectionTest extends AbstractConnectionTest
httpClient.setConnectBlocking(false);
return httpClient;
}
+
+ @Override
+ public void testServerHalfClosedIncomplete() throws Exception
+ {
+ super.testServerHalfClosedIncomplete();
+ }
+
+
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java
index f5ac43dc403..2c878e273d5 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java
@@ -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();
}
+
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalKeyStoreAsyncSslHttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalKeyStoreAsyncSslHttpExchangeTest.java
index 445947e3534..27af22c21ed 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalKeyStoreAsyncSslHttpExchangeTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalKeyStoreAsyncSslHttpExchangeTest.java
@@ -13,28 +13,23 @@
package org.eclipse.jetty.client;
-import java.io.FileInputStream;
-
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
+import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
{
- @Override
- public void setUp() throws Exception
+ private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
+
+ @Before
+ public void setUpOnce() throws Exception
{
- _scheme = "https";
- startServer();
- _httpClient = new HttpClient();
- _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
- _httpClient.setMaxConnectionsPerAddress(2);
-
- String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
-
- _httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
- _httpClient.setKeyStorePassword("storepwd");
- _httpClient.setKeyManagerPassword("keypwd");
- _httpClient.start();
+ _scheme="https";
+ _server = serverAndClientCreator.createServer();
+ _httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
+ _port = _server.getConnectors()[0].getLocalPort();
}
@Override
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAsserts.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAsserts.java
new file mode 100644
index 00000000000..e0410057571
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAsserts.java
@@ -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 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());
+ }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java
index 09de4467204..3b84bfec975 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java
@@ -13,14 +13,9 @@
package org.eclipse.jetty.client;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -30,13 +25,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import org.eclipse.jetty.client.helperClasses.HttpServerAndClientCreator;
+import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
import org.eclipse.jetty.client.security.ProxyAuthorization;
import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Buffer;
@@ -44,17 +36,13 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.toolchain.test.Stress;
-import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/* ------------------------------------------------------------ */
@@ -63,37 +51,44 @@ import org.junit.Test;
*/
public class HttpExchangeTest
{
- private static final Logger LOG = Log.getLogger(HttpExchangeTest.class);
-
- protected int _maxConnectionsPerAddress = 2;
- protected String _scheme = "http";
- protected Server _server;
- protected int _port;
- protected HttpClient _httpClient;
- protected Connector _connector;
- protected AtomicInteger _count = new AtomicInteger();
+ final static boolean verbose=false;
+ protected static int _maxConnectionsPerAddress = 2;
+ protected static String _scheme = "http";
+ protected static Server _server;
+ protected static int _port;
+ protected static HttpClient _httpClient;
+ protected static AtomicInteger _count = new AtomicInteger();
+ protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
+
+ protected static URI getBaseURI()
+ {
+ return URI.create(_scheme + "://localhost:" + _port + "/");
+ }
/* ------------------------------------------------------------ */
+ // TODO work out why BeforeClass does not work here?
@Before
- public void setUp() throws Exception
+ public void setUpOnce() throws Exception
{
- startServer();
- _httpClient=new HttpClient();
- _httpClient.setIdleTimeout(3000);
- _httpClient.setTimeout(3500);
- _httpClient.setConnectTimeout(2000);
- _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
- _httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
- _httpClient.start();
+ _scheme = "http";
+ _server = serverAndClientCreator.createServer();
+ _httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
+ _port = _server.getConnectors()[0].getLocalPort();
}
/* ------------------------------------------------------------ */
@After
- public void tearDown() throws Exception
+ public void tearDownOnce() throws Exception
{
_httpClient.stop();
- Thread.sleep(500);
- stopServer();
+ long startTime = System.currentTimeMillis();
+ while (!_httpClient.getState().equals(AbstractLifeCycle.STOPPED))
+ {
+ if (System.currentTimeMillis() - startTime > 1000)
+ break;
+ Thread.sleep(5);
+ }
+ _server.stop();
}
/* ------------------------------------------------------------ */
@@ -110,7 +105,9 @@ public class HttpExchangeTest
{
sender(1,false);
sender(1,true);
-
+ sender(10,false);
+ sender(10,true);
+
if (Stress.isEnabled())
{
sender(100,false);
@@ -118,67 +115,72 @@ public class HttpExchangeTest
sender(10000,false);
sender(10000,true);
}
- else
- {
- sender(10,false);
- sender(10,true);
- }
}
/* ------------------------------------------------------------ */
/**
* Test sending data through the exchange.
- *
+ *
* @throws IOException
*/
- public void sender(final int nb,final boolean close) throws Exception
+ public void sender(final int nb, final boolean close) throws Exception
{
_count.set(0);
- final CountDownLatch complete=new CountDownLatch(nb);
- final CountDownLatch latch=new CountDownLatch(nb);
+ final CountDownLatch complete = new CountDownLatch(nb);
+ final AtomicInteger allcontent = new AtomicInteger(nb);
HttpExchange[] httpExchange = new HttpExchange[nb];
- long start=System.currentTimeMillis();
- for (int i=0; i "+len);
}
/* ------------------------------------------------------------ */
@Override
protected void onResponseComplete()
{
- result="complete";
- if (len==2009)
- latch.countDown();
+ if (verbose)
+ System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
+ result = "complete";
+ if (len == 2009)
+ allcontent.decrementAndGet();
else
- {
- System.err.println(n+" ONLY "+len);
- }
+ System.err.println(n + " ONLY " + len+ "/2009");
complete.countDown();
}
@@ -207,9 +211,11 @@ public class HttpExchangeTest
@Override
protected void onConnectionFailed(Throwable ex)
{
+ if (verbose)
+ System.err.println("] "+ex);
complete.countDown();
- result="failed";
- System.err.println(n+" FAILED "+ex);
+ result = "failed";
+ System.err.println(n + " FAILED " + ex);
super.onConnectionFailed(ex);
}
@@ -217,9 +223,11 @@ public class HttpExchangeTest
@Override
protected void onException(Throwable ex)
{
+ if (verbose)
+ System.err.println("] "+ex);
complete.countDown();
- result="excepted";
- System.err.println(n+" EXCEPTED "+ex);
+ result = "excepted";
+ System.err.println(n + " EXCEPTED " + ex);
super.onException(ex);
}
@@ -227,9 +235,11 @@ public class HttpExchangeTest
@Override
protected void onExpire()
{
+ if (verbose)
+ System.err.println("] expired");
complete.countDown();
- result="expired";
- System.err.println(n+" EXPIRED "+len);
+ result = "expired";
+ System.err.println(n + " EXPIRED " + len);
super.onExpire();
}
@@ -237,29 +247,24 @@ public class HttpExchangeTest
@Override
public String toString()
{
- return n+" "+result+" "+len;
+ return n+"/"+result+"/"+len+"/"+super.toString();
}
};
- httpExchange[n].setURL(_scheme+"://localhost:"+_port+"/"+n);
+ httpExchange[n].setURI(getBaseURI().resolve("/" + n));
httpExchange[n].addRequestHeader("arbitrary","value");
if (close)
httpExchange[n].setRequestHeader("Connection","close");
_httpClient.send(httpExchange[n]);
}
-
- assertTrue(complete.await(45,TimeUnit.SECONDS));
-
- long elapsed=System.currentTimeMillis()-start;
- // make windows-friendly ... System.currentTimeMillis() on windows is dope!
- /*
- if(elapsed>0)
- System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
- */
+ if (!complete.await(2,TimeUnit.SECONDS))
+ System.err.println(_httpClient.dump());
- assertEquals("nb="+nb+" close="+close,0,latch.getCount());
+ assertTrue(complete.await(20,TimeUnit.SECONDS));
+
+ assertEquals("nb="+nb+" close="+close,0,allcontent.get());
}
/* ------------------------------------------------------------ */
@@ -269,7 +274,7 @@ public class HttpExchangeTest
for (int i=0;i<20;i++)
{
ContentExchange httpExchange=new ContentExchange();
- httpExchange.setURI(new URI(_scheme, null, "localhost", _port, null, null, null));
+ httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContent(new ByteArrayBuffer(""));
_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(""));
assertEquals("i="+i,result.length()-10,result.indexOf(""));
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(""));
assertEquals("i="+i,result.length()-10,result.indexOf(""));
assertEquals(HttpExchange.STATUS_COMPLETED, status);
@@ -355,7 +361,7 @@ public class HttpExchangeTest
throwable.set(x);
}
};
- httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
+ httpExchange.setURI(getBaseURI());
httpExchange.setMethod("SLEEP");
_httpClient.send(httpExchange);
new Thread()
@@ -374,6 +380,7 @@ public class HttpExchangeTest
System.err.println(throwable.get());
assertTrue(throwable.get().toString().indexOf("close")>=0);
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
+ _httpClient.start();
}
/* ------------------------------------------------------------ */
@@ -381,7 +388,54 @@ public class HttpExchangeTest
public void testBigPostWithContentExchange() throws Exception
{
int size =32;
- ContentExchange httpExchange=new ContentExchange();
+ ContentExchange httpExchange=new ContentExchange()
+ {
+ int total;
+
+ @Override
+ protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
+ {
+ if (verbose)
+ System.err.println("] "+version+" "+status+" "+reason);
+ super.onResponseStatus(version,status,reason);
+ }
+
+ @Override
+ protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException
+ {
+ if (verbose)
+ System.err.println("] "+name+": "+value);
+ super.onResponseHeader(name,value);
+ }
+
+ @Override
+ protected synchronized void onResponseContent(Buffer content) throws IOException
+ {
+ if (verbose)
+ {
+ total+=content.length();
+ System.err.println("] "+content.length()+" -> "+total);
+ }
+ super.onResponseContent(content);
+ }
+
+ @Override
+ protected void onRequestComplete() throws IOException
+ {
+ if (verbose)
+ System.err.println("] ==");
+ super.onRequestComplete();
+ }
+
+ @Override
+ protected void onResponseHeaderComplete() throws IOException
+ {
+ if (verbose)
+ System.err.println("] --");
+ super.onResponseHeaderComplete();
+ }
+
+ };
Buffer babuf = new ByteArrayBuffer(size*36*1024);
Buffer niobuf = new DirectNIOBuffer(size*36*1024);
@@ -394,28 +448,27 @@ public class HttpExchangeTest
niobuf.put(bytes);
}
- httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
+ httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(babuf);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
-
assertEquals(HttpExchange.STATUS_COMPLETED,status);
String result=httpExchange.getResponseContent();
assertEquals(babuf.length(),result.length());
httpExchange.reset();
- httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
+ httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(niobuf);
_httpClient.send(httpExchange);
status = httpExchange.waitForDone();
+ assertEquals(HttpExchange.STATUS_COMPLETED, status);
result=httpExchange.getResponseContent();
assertEquals(niobuf.length(),result.length());
- assertEquals(HttpExchange.STATUS_COMPLETED, status);
}
/* ------------------------------------------------------------ */
@@ -426,7 +479,7 @@ public class HttpExchangeTest
{
};
- httpExchange.setURL(_scheme+"://localhost:"+_port);
+ httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
final String data="012345678901234567890123456789012345678901234567890123456789";
@@ -447,7 +500,7 @@ public class HttpExchangeTest
@Override
public int read(byte[] b, int off, int len) throws IOException
{
- if (_index>=data.length())
+ if (_index >= data.length())
return -1;
try
@@ -458,28 +511,28 @@ public class HttpExchangeTest
{
e.printStackTrace();
}
-
- int l=0;
- while (l<5 && _index=0)
+ while ((len = in.read(buffer)) >= 0)
{
out.write(buffer,0,len);
}
}
catch (EofException e)
{
- System.err.println("HttpExchangeTest#copyStream: "+e);
+ System.err.println("HttpExchangeTest#copyStream: " + e);
}
catch (IOException e)
{
e.printStackTrace();
}
}
-
- /* ------------------------------------------------------------ */
- protected void newServer() throws Exception
- {
- _server=new Server();
- _server.setGracefulShutdown(500);
- _connector=new SelectChannelConnector();
-
- _connector.setMaxIdleTime(3000000);
-
- _connector.setPort(0);
- _server.setConnectors(new Connector[] { _connector });
- }
-
- /* ------------------------------------------------------------ */
- protected void startServer() throws Exception
- {
- newServer();
- _server.setHandler(new AbstractHandler()
- {
- public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
- {
- int i=0;
- try
- {
- baseRequest.setHandled(true);
- response.setStatus(200);
- _count.incrementAndGet();
-
- if (request.getServerName().equals("jetty.eclipse.org"))
- {
- response.getOutputStream().println("Proxy request: "+request.getRequestURL());
- response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
- }
- else if (request.getMethod().equalsIgnoreCase("GET"))
- {
- response.getOutputStream().println("");
- for (; i<100; i++)
- {
- response.getOutputStream().println(" "+i+"");
- }
- 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();
- }
-
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java
index 2970de67aa9..4438463ce2d 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SocketConnectionTest.java
@@ -13,6 +13,16 @@
package org.eclipse.jetty.client;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.CountDownLatch;
+
+import static org.junit.Assert.assertEquals;
+
public class SocketConnectionTest extends AbstractConnectionTest
{
protected HttpClient newHttpClient()
@@ -21,10 +31,61 @@ public class SocketConnectionTest extends AbstractConnectionTest
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
return httpClient;
}
-
+
@Override
- public void testServerClosedConnection()
+ public void testServerClosedConnection() throws Exception
{
- // TODO work out why this does not work
+ // Differently from the SelectConnector, the SocketConnector cannot detect server closes.
+ // Therefore, upon a second send, the exchange will fail.
+ // Applications needs to retry it explicitly.
+
+ ServerSocket serverSocket = new ServerSocket();
+ serverSocket.bind(null);
+ int port=serverSocket.getLocalPort();
+
+ HttpClient httpClient = this.newHttpClient();
+ httpClient.setMaxConnectionsPerAddress(1);
+ httpClient.start();
+ try
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+ HttpExchange exchange = new ConnectionExchange(latch);
+ exchange.setAddress(new Address("localhost", port));
+ exchange.setRequestURI("/");
+ httpClient.send(exchange);
+
+ Socket remote = serverSocket.accept();
+
+ // HttpClient.send() above is async, so if we write the response immediately
+ // there is a chance that it arrives before the request is being sent, so we
+ // read the request before sending the response to avoid the race
+ InputStream input = remote.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.length() == 0)
+ break;
+ }
+
+ OutputStream output = remote.getOutputStream();
+ output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
+ output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
+ output.write("\r\n".getBytes("UTF-8"));
+ output.flush();
+
+ assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
+
+ remote.close();
+
+ exchange.reset();
+ httpClient.send(exchange);
+
+ assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
+ }
+ finally
+ {
+ httpClient.stop();
+ }
}
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java
index 6ea97bc5aa4..8ec13c1ef21 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SslHttpExchangeTest.java
@@ -13,67 +13,36 @@
package org.eclipse.jetty.client;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.*;
-import org.eclipse.jetty.http.ssl.SslContextFactory;
+import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
+import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ssl.SslSocketConnector;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.Stress;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/**
* Functional testing for HttpExchange.
- *
- *
- *
*/
public class SslHttpExchangeTest extends HttpExchangeTest
{
+ protected static ServerAndClientCreator serverAndClientCreator = new SslServerAndClientCreator();
+
/* ------------------------------------------------------------ */
@Before
- @Override
- public void setUp() throws Exception
+ public void setUpOnce() throws Exception
{
_scheme="https";
- startServer();
- _httpClient=new HttpClient();
- _httpClient.setIdleTimeout(2000);
- _httpClient.setTimeout(2500);
- _httpClient.setConnectTimeout(1000);
- _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
- _httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
- _httpClient.setMaxConnectionsPerAddress(2);
- _httpClient.start();
+ _server = serverAndClientCreator.createServer();
+ _httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
+ Connector[] connectors = _server.getConnectors();
+ _port = connectors[0].getLocalPort();
}
- /* ------------------------------------------------------------ */
- @Override
- protected void newServer()
- {
- _server = new Server();
- //SslSelectChannelConnector connector = new SslSelectChannelConnector();
- SslSocketConnector connector = new SslSocketConnector();
-
- String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
-
- connector.setPort(0);
- SslContextFactory cf = connector.getSslContextFactory();
- cf.setKeyStore(keystore);
- cf.setKeyStorePassword("storepwd");
- cf.setKeyManagerPassword("keypwd");
- connector.setAllowRenegotiate(true);
-
- _server.setConnectors(new Connector[]
- { connector });
- _connector=connector;
- }
-
/* ------------------------------------------------------------ */
private void IgnoreTestOnBuggyIBM()
{
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java
new file mode 100644
index 00000000000..d7df2a39168
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AbstractSslServerAndClientCreator.java
@@ -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;
+ }
+
+
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java
new file mode 100644
index 00000000000..6d08d216f90
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/AsyncSslServerAndClientCreator.java
@@ -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;
+ }
+
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java
new file mode 100644
index 00000000000..584f4b1a64b
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ExternalKeyStoreAsyncSslServerAndClientCreator.java
@@ -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;
+ }
+
+
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java
new file mode 100644
index 00000000000..82dbdb35c47
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/GenericServerHandler.java
@@ -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("");
+ for (; i < 100; i++)
+ {
+ response.getOutputStream().println(" " + i + "");
+ }
+ 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);
+ }
+ }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java
new file mode 100644
index 00000000000..d9a2f1d3eef
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/HttpServerAndClientCreator.java
@@ -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;
+ }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java
new file mode 100644
index 00000000000..015006f6802
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/ServerAndClientCreator.java
@@ -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;
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java
new file mode 100644
index 00000000000..d0e0ad0a115
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/helperClasses/SslServerAndClientCreator.java
@@ -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;
+ }
+}
diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml
index 46cad3e98eb..e49d6d28c9c 100644
--- a/jetty-distribution/pom.xml
+++ b/jetty-distribution/pom.xml
@@ -155,157 +155,6 @@
maven-dependency-plugin
-
- unpack
- generate-resources
-
- unpack
-
-
-
-
- org.eclipse.jetty
- jetty-rewrite
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-ajp
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- test-jetty-webapp
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-jmx
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-util
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-webapp
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-deploy
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-plus
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-server
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-security
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-policy
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-monitor
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-overlay-deployer
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
- org.eclipse.jetty
- jetty-annotations
- ${project.version}
- config
- jar
- true
- **
- ${assembly-directory}
-
-
-
- copygenerate-resources
@@ -324,187 +173,6 @@
${assembly-directory}/VERSION.txt
-
- org.eclipse.jetty
- jetty-util
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-io
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-http
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-server
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-security
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-servlet
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-servlets
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-xml
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-webapp
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
-
- org.eclipse.jetty
- jetty-deploy
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-jmx
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-rewrite
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-ajp
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-annotations
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-client
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-jndi
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-policy
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-monitor
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib/monitor
-
-
- org.eclipse.jetty
- jetty-plus
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-continuation
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
- org.eclipse.jettytest-jetty-webapp
@@ -525,36 +193,77 @@
${assembly-directory}start.jar
-
- org.eclipse.jetty
- jetty-overlay-deployer
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-overlay-deployer
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
-
- org.eclipse.jetty
- jetty-websocket
- ${project.version}
- jar
- true
- **
- ${assembly-directory}/lib
-
+
+ copy-lib-deps
+ generate-resources
+
+ copy-dependencies
+
+
+ org.eclipse.jetty
+ jetty-start,jetty-monitor,jetty-jsp-2.1
+ jar
+ ${assembly-directory}/lib
+
+
+
+ copy-lib-jsp-deps
+ generate-resources
+
+ copy-dependencies
+
+
+ org.eclipse.jetty,org.glassfish.web
+ jetty-jsp-2.1,jsp-impl
+ jar
+ ${assembly-directory}/lib/jsp
+
+
+
+ copy-lib-monitor-deps
+ generate-resources
+
+ copy-dependencies
+
+
+ org.eclipse.jetty
+ jetty-monitor
+ jar
+ true
+ ${assembly-directory}/lib/monitor
+
+
+
+ unpack-config-deps
+ generate-resources
+
+ unpack-dependencies
+
+
+ org.eclipse.jetty
+ config
+ false
+ ${assembly-directory}
+
+
+
+ unpack-javadoc
+ generate-resources
+
+ unpack-dependencies
+
+
+
+ org.eclipse.jetty.aggregate
+ jetty-all
+ javadoc
+ true
+ ${assembly-directory}/javadoc
+
+
@@ -663,12 +372,12 @@
org.eclipse.jetty
- jetty-overlay-deployer
+ jetty-servlets${project.version}org.eclipse.jetty
- jetty-overlay-deployer
+ jetty-monitor${project.version}
@@ -676,5 +385,17 @@
jetty-websocket${project.version}
+
+ org.eclipse.jetty
+ jetty-overlay-deployer
+ ${project.version}
+
+
+ org.eclipse.jetty.aggregate
+ jetty-all
+ javadoc
+ jar
+ ${project.version}
+
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
index 50f58ae63f1..6901fe1f63f 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java
@@ -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)
{
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index aecc18b069c..572a0390379 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -4,15 +4,16 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
-// The Eclipse Public License is available at
+// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
-// You may elect to redistribute this code under either of these licenses.
+// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.http;
+import java.io.EOFException;
import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
@@ -67,7 +68,7 @@ public class HttpParser implements Parser
private String _multiLineValue;
private int _responseStatus; // If >0 then we are parsing a response
private boolean _forceContentBuffer;
-
+
/* ------------------------------------------------------------------------------- */
protected final View _contentView=new View(); // View of the content in the buffer for {@link Input}
protected int _state=STATE_START;
@@ -78,7 +79,7 @@ public class HttpParser implements Parser
protected int _chunkLength;
protected int _chunkPosition;
private boolean _headResponse;
-
+
/* ------------------------------------------------------------------------------- */
/**
* Constructor.
@@ -103,7 +104,7 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
/**
* Constructor.
- * @param buffers the buffers to use
+ * @param buffers the buffers to use
* @param endp the endpoint
* @param handler the even handler
*/
@@ -134,7 +135,7 @@ public class HttpParser implements Parser
{
_headResponse=head;
}
-
+
/* ------------------------------------------------------------------------------- */
public int getState()
{
@@ -170,7 +171,7 @@ public class HttpParser implements Parser
{
return isState(STATE_END);
}
-
+
/* ------------------------------------------------------------ */
public boolean isMoreInBuffer()
throws IOException
@@ -203,11 +204,11 @@ public class HttpParser implements Parser
if (parseNext()<0)
return;
}
-
+
/* ------------------------------------------------------------------------------- */
/**
* Parse until END state.
- * This method will parse any remaining content in the current buffer. It does not care about the
+ * This method will parse any remaining content in the current buffer. It does not care about the
* {@link #getState current state} of the parser.
* @see #parse
* @see #parseNext
@@ -216,7 +217,7 @@ public class HttpParser implements Parser
{
int progress = parseNext();
int total=progress>0?1:0;
-
+
// continue parsing
while (!isComplete() && _buffer!=null && _buffer.length()>0)
{
@@ -237,9 +238,9 @@ public class HttpParser implements Parser
{
int progress=0;
- if (_state == STATE_END)
+ if (_state == STATE_END)
return 0;
-
+
if (_buffer==null)
{
if (_header == null)
@@ -252,23 +253,33 @@ public class HttpParser implements Parser
_tok0.setPutIndex(_tok0.getIndex());
_tok1.setPutIndex(_tok1.getIndex());
}
-
-
+
+
if (_state == STATE_CONTENT && _contentPosition == _contentLength)
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
return 1;
}
-
+
int length=_buffer.length();
-
+
// Fill buffer if we can
if (length == 0)
{
- long filled=fill();
-
- if (filled < 0)
+ long filled=-1;
+ IOException ex=null;
+ try
+ {
+ filled=fill();
+ }
+ catch(IOException e)
+ {
+ LOG.debug(this.toString(),e);
+ ex=e;
+ }
+
+ if (filled < 0 || _endp.isInputShutdown())
{
if (_headResponse && _state>STATE_END)
{
@@ -284,19 +295,25 @@ public class HttpParser implements Parser
Buffer chunk=_buffer.get(_buffer.length());
_contentPosition += chunk.length();
_contentView.update(chunk);
- _handler.content(chunk); // May recurse here
+ _handler.content(chunk); // May recurse here
}
_state=STATE_END;
_handler.messageComplete(_contentPosition);
return 1;
}
-
+
+ if (ex!=null)
+ throw ex;
+
+ if (!isComplete() && !isIdle())
+ throw new EOFException();
+
return -1;
}
length=_buffer.length();
}
-
+
// EventHandler header
byte ch;
byte[] array=_buffer.array();
@@ -308,16 +325,16 @@ public class HttpParser implements Parser
progress++;
last=_state;
}
-
+
ch=_buffer.get();
-
+
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
{
_eol=HttpTokens.LINE_FEED;
continue;
}
_eol=0;
-
+
switch (_state)
{
case STATE_START:
@@ -464,22 +481,22 @@ public class HttpParser implements Parser
_state=STATE_HEADER_VALUE;
break;
}
-
+
default:
{
// handler last header if any
if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
{
-
+
Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
_cached=null;
Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
-
+
int ho=HttpHeaders.CACHE.getOrdinal(header);
if (ho >= 0)
{
- int vo;
-
+ int vo;
+
switch (ho)
{
case HttpHeaders.CONTENT_LENGTH_ORDINAL:
@@ -498,7 +515,7 @@ public class HttpParser implements Parser
_contentLength=HttpTokens.NO_CONTENT;
}
break;
-
+
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
value=HttpHeaderValues.CACHE.lookup(value);
vo=HttpHeaderValues.CACHE.getOrdinal(value);
@@ -509,22 +526,22 @@ public class HttpParser implements Parser
String c=value.toString(StringUtil.__ISO_8859_1);
if (c.endsWith(HttpHeaderValues.CHUNKED))
_contentLength=HttpTokens.CHUNKED_CONTENT;
-
+
else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
throw new HttpException(400,null);
}
break;
}
}
-
+
_handler.parsedHeader(header, value);
_tok0.setPutIndex(_tok0.getIndex());
_tok1.setPutIndex(_tok1.getIndex());
_multiLineValue=null;
}
_buffer.setMarkIndex(-1);
-
-
+
+
// now handle ch
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
@@ -544,7 +561,7 @@ public class HttpParser implements Parser
_eol=ch;
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
_eol=_buffer.get();
-
+
// We convert _contentLength to an int for this switch statement because
// we don't care about the amount of data available just whether there is some.
switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
@@ -553,19 +570,19 @@ public class HttpParser implements Parser
_state=STATE_EOF_CONTENT;
_handler.headerComplete(); // May recurse here !
break;
-
+
case HttpTokens.CHUNKED_CONTENT:
_state=STATE_CHUNKED_CONTENT;
_handler.headerComplete(); // May recurse here !
break;
-
+
case HttpTokens.NO_CONTENT:
_state=STATE_END;
returnBuffers();
- _handler.headerComplete();
+ _handler.headerComplete();
_handler.messageComplete(_contentPosition);
break;
-
+
default:
_state=STATE_CONTENT;
_handler.headerComplete(); // May recurse here !
@@ -579,7 +596,7 @@ public class HttpParser implements Parser
_length=1;
_buffer.mark();
_state=STATE_HEADER_NAME;
-
+
// try cached name!
if (array!=null)
{
@@ -592,10 +609,10 @@ public class HttpParser implements Parser
length=_buffer.length();
}
}
- }
+ }
}
}
-
+
break;
case STATE_HEADER_NAME:
@@ -617,16 +634,16 @@ public class HttpParser implements Parser
case HttpTokens.SPACE:
case HttpTokens.TAB:
break;
- default:
+ default:
{
_cached=null;
- if (_length == -1)
+ if (_length == -1)
_buffer.mark();
_length=_buffer.getIndex() - _buffer.markIndex();
- _state=STATE_HEADER_IN_NAME;
+ _state=STATE_HEADER_IN_NAME;
}
}
-
+
break;
case STATE_HEADER_IN_NAME:
@@ -682,11 +699,11 @@ public class HttpParser implements Parser
break;
default:
{
- if (_length == -1)
+ if (_length == -1)
_buffer.mark();
_length=_buffer.getIndex() - _buffer.markIndex();
_state=STATE_HEADER_IN_VALUE;
- }
+ }
}
break;
@@ -720,9 +737,9 @@ public class HttpParser implements Parser
break;
}
} // end of HEADER states loop
-
+
// ==========================
-
+
// Handle HEAD response
if (_responseStatus>0 && _headResponse)
{
@@ -731,10 +748,10 @@ public class HttpParser implements Parser
}
// ==========================
-
+
// Handle _content
length=_buffer.length();
- Buffer chunk;
+ Buffer chunk;
last=_state;
while (_state > STATE_END && length > 0)
{
@@ -743,7 +760,7 @@ public class HttpParser implements Parser
progress++;
last=_state;
}
-
+
if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
{
_eol=_buffer.get();
@@ -757,11 +774,11 @@ public class HttpParser implements Parser
chunk=_buffer.get(_buffer.length());
_contentPosition += chunk.length();
_contentView.update(chunk);
- _handler.content(chunk); // May recurse here
+ _handler.content(chunk); // May recurse here
// TODO adjust the _buffer to keep unconsumed content
return 1;
- case STATE_CONTENT:
+ case STATE_CONTENT:
{
long remaining=_contentLength - _contentPosition;
if (remaining == 0)
@@ -770,24 +787,24 @@ public class HttpParser implements Parser
_handler.messageComplete(_contentPosition);
return 1;
}
-
- if (length > remaining)
+
+ if (length > remaining)
{
// We can cast reamining to an int as we know that it is smaller than
- // or equal to length which is already an int.
+ // or equal to length which is already an int.
length=(int)remaining;
}
-
+
chunk=_buffer.get(length);
_contentPosition += chunk.length();
_contentView.update(chunk);
- _handler.content(chunk); // May recurse here
-
+ _handler.content(chunk); // May recurse here
+
if(_contentPosition == _contentLength)
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
- }
+ }
// TODO adjust the _buffer to keep unconsumed content
return 1;
}
@@ -814,7 +831,7 @@ public class HttpParser implements Parser
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
_eol=ch;
-
+
if (_chunkLength == 0)
{
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
@@ -858,8 +875,8 @@ public class HttpParser implements Parser
}
break;
}
-
- case STATE_CHUNK:
+
+ case STATE_CHUNK:
{
int remaining=_chunkLength - _chunkPosition;
if (remaining == 0)
@@ -867,13 +884,13 @@ public class HttpParser implements Parser
_state=STATE_CHUNKED_CONTENT;
break;
}
- else if (length > remaining)
+ else if (length > remaining)
length=remaining;
chunk=_buffer.get(length);
_contentPosition += chunk.length();
_chunkPosition += chunk.length();
_contentView.update(chunk);
- _handler.content(chunk); // May recurse here
+ _handler.content(chunk); // May recurse here
// TODO adjust the _buffer to keep unconsumed content
return 1;
}
@@ -881,13 +898,13 @@ public class HttpParser implements Parser
length=_buffer.length();
}
-
+
return progress;
}
/* ------------------------------------------------------------------------------- */
/** fill the buffers from the endpoint
- *
+ *
*/
public long fill() throws IOException
{
@@ -898,14 +915,14 @@ public class HttpParser implements Parser
_tok0=new View.CaseInsensitive(_buffer);
_tok1=new View.CaseInsensitive(_buffer);
}
-
+
// Is there unconsumed content in body buffer
if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
{
_buffer=_body;
return _buffer.length();
}
-
+
// Shall we switch to a body buffer?
if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
{
@@ -913,20 +930,20 @@ public class HttpParser implements Parser
_body=_buffers.getBuffer();
_buffer=_body;
}
-
+
// Do we have somewhere to fill from?
if (_endp != null )
{
// Shall we compact the body?
- if (_buffer==_body || _state>STATE_END)
+ if (_buffer==_body || _state>STATE_END)
{
_buffer.compact();
}
-
+
// Are we full?
- if (_buffer.space() == 0)
- throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
-
+ if (_buffer.space() == 0)
+ throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
+
try
{
return _endp.fill(_buffer);
@@ -943,7 +960,7 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
/** Skip any CRLFs in buffers
- *
+ *
*/
public void skipCRLF()
{
@@ -971,12 +988,12 @@ public class HttpParser implements Parser
else
break;
}
-
+
}
-
+
/* ------------------------------------------------------------------------------- */
public void reset()
- {
+ {
// reset state
_contentView.setGetIndex(_contentView.putIndex());
_state=STATE_START;
@@ -1026,12 +1043,12 @@ public class HttpParser implements Parser
public void returnBuffers()
{
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
- {
+ {
if (_buffer==_body)
_buffer=_header;
if (_buffers!=null)
_buffers.returnBuffer(_body);
- _body=null;
+ _body=null;
}
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
@@ -1042,7 +1059,7 @@ public class HttpParser implements Parser
_header=null;
}
}
-
+
/* ------------------------------------------------------------------------------- */
public void setState(int state)
{
@@ -1055,13 +1072,13 @@ public class HttpParser implements Parser
{
return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
}
-
+
/* ------------------------------------------------------------------------------- */
@Override
public String toString()
{
return "state=" + _state + " length=" + _length + " len=" + _contentLength;
- }
+ }
/* ------------------------------------------------------------ */
public Buffer getHeaderBuffer()
@@ -1072,7 +1089,7 @@ public class HttpParser implements Parser
}
return _header;
}
-
+
/* ------------------------------------------------------------ */
public Buffer getBodyBuffer()
{
@@ -1086,20 +1103,20 @@ public class HttpParser implements Parser
public void setForceContentBuffer(boolean force)
{
_forceContentBuffer=force;
- }
-
+ }
+
/* ------------------------------------------------------------ */
public Buffer blockForContent(long maxIdleTime) throws IOException
{
if (_contentView.length()>0)
return _contentView;
- if (getState() <= HttpParser.STATE_END)
+ if (getState() <= HttpParser.STATE_END)
return null;
-
+
try
{
parseNext();
-
+
// parse until some progress is made (or IOException thrown for timeout)
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp!=null && _endp.isOpen())
{
@@ -1123,9 +1140,9 @@ public class HttpParser implements Parser
_endp.close();
throw e;
}
-
- return _contentView.length()>0?_contentView:null;
- }
+
+ return _contentView.length()>0?_contentView:null;
+ }
/* ------------------------------------------------------------ */
/* (non-Javadoc)
@@ -1143,11 +1160,11 @@ public class HttpParser implements Parser
return 0;
}
-
+
parseNext();
return _contentView==null?0:_contentView.length();
}
-
+
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@@ -1175,7 +1192,7 @@ public class HttpParser implements Parser
*/
public abstract void startRequest(Buffer method, Buffer url, Buffer version)
throws IOException;
-
+
/**
* This is the method called by parser when the HTTP request line is parsed
*/
@@ -1185,5 +1202,5 @@ public class HttpParser implements Parser
-
+
}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
index 7e24daa3ebf..19da9e00104 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
@@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
-// The Eclipse Public License is available at
+// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
-// You may elect to redistribute this code under either of these licenses.
+// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.http;
@@ -34,7 +34,7 @@ import org.eclipse.jetty.util.URIUtil;
* /foo/bar - an exact path specification.
* /foo/* - a prefix path specification (must end '/*').
* *.ext - a suffix path specification.
- * / - the default path specification.
+ * / - the default path specification.
*
* Matching is performed in the following order
*
* Multiple path specifications can be mapped by providing a list of
- * specifications. By default this class uses characters ":," as path
- * separators, unless configured differently by calling the static
- * method @see PathMap#setPathSpecSeparators(String)
+ * specifications. By default this class uses characters ":," as path
+ * separators, unless configured differently by calling the static
+ * method @see PathMap#setPathSpecSeparators(String)
*
* Special characters within paths such as '?� and ';' are not treated specially
- * as it is assumed they would have been either encoded in the original URL or
+ * as it is assumed they would have been either encoded in the original URL or
* stripped from the path.
*
* This class is not synchronized. If concurrent modifications are
* possible then it should be synchronized at a higher level.
*
- *
+ *
*/
public class PathMap extends HashMap implements Externalizable
{
/* ------------------------------------------------------------ */
private static String __pathSpecSeparators = ":,";
-
+
/* ------------------------------------------------------------ */
/** Set the path spec separator.
* Multiple path specification may be included in a single string
@@ -72,7 +72,7 @@ public class PathMap extends HashMap implements Externalizable
{
__pathSpecSeparators=s;
}
-
+
/* --------------------------------------------------------------- */
final StringMap _prefixMap=new StringMap();
final StringMap _suffixMap=new StringMap();
@@ -83,7 +83,7 @@ public class PathMap extends HashMap implements Externalizable
Entry _default=null;
final Set _entrySet;
boolean _nodefault=false;
-
+
/* --------------------------------------------------------------- */
/** Construct empty PathMap.
*/
@@ -102,7 +102,7 @@ public class PathMap extends HashMap implements Externalizable
_entrySet=entrySet();
_nodefault=nodefault;
}
-
+
/* --------------------------------------------------------------- */
/** Construct empty PathMap.
*/
@@ -111,7 +111,7 @@ public class PathMap extends HashMap implements Externalizable
super (capacity);
_entrySet=entrySet();
}
-
+
/* --------------------------------------------------------------- */
/** Construct from dictionary PathMap.
*/
@@ -120,7 +120,7 @@ public class PathMap extends HashMap implements Externalizable
putAll(m);
_entrySet=entrySet();
}
-
+
/* ------------------------------------------------------------ */
public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException
@@ -128,7 +128,7 @@ public class PathMap extends HashMap implements Externalizable
HashMap map = new HashMap(this);
out.writeObject(map);
}
-
+
/* ------------------------------------------------------------ */
public void readExternal(java.io.ObjectInput in)
throws java.io.IOException, ClassNotFoundException
@@ -136,7 +136,7 @@ public class PathMap extends HashMap implements Externalizable
HashMap map = (HashMap)in.readObject();
this.putAll(map);
}
-
+
/* --------------------------------------------------------------- */
/** Add a single path match to the PathMap.
* @param pathSpec The path specification, or comma separated list of
@@ -148,16 +148,16 @@ public class PathMap extends HashMap implements Externalizable
{
StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators);
Object old =null;
-
+
while (tok.hasMoreTokens())
{
String spec=tok.nextToken();
-
+
if (!spec.startsWith("/") && !spec.startsWith("*."))
throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'");
-
+
old = super.put(spec,object);
-
+
// Make entry that was just created.
Entry entry = new Entry(spec,object);
@@ -176,7 +176,7 @@ public class PathMap extends HashMap implements Externalizable
else if (spec.startsWith("*."))
_suffixMap.put(spec.substring(2),entry);
else if (spec.equals(URIUtil.SLASH))
- {
+ {
if (_nodefault)
_exactMap.put(spec,entry);
else
@@ -193,7 +193,7 @@ public class PathMap extends HashMap implements Externalizable
}
}
}
-
+
return old;
}
@@ -209,8 +209,8 @@ public class PathMap extends HashMap implements Externalizable
return entry.getValue();
return null;
}
-
-
+
+
/* --------------------------------------------------------------- */
/** Get the entry mapped by the best specification.
* @param path the path.
@@ -222,14 +222,14 @@ public class PathMap extends HashMap implements Externalizable
if (path==null)
return null;
-
- int l=path.length();
+
+ int l=path.length();
// try exact match
entry=_exactMap.getEntry(path,0,l);
if (entry!=null)
return (Entry) entry.getValue();
-
+
// prefix search
int i=l;
while((i=path.lastIndexOf('/',i-1))>=0)
@@ -238,11 +238,11 @@ public class PathMap extends HashMap implements Externalizable
if (entry!=null)
return (Entry) entry.getValue();
}
-
+
// Prefix Default
if (_prefixDefault!=null)
return _prefixDefault;
-
+
// Extension search
i=0;
while ((i=path.indexOf('.',i+1))>0)
@@ -250,12 +250,12 @@ public class PathMap extends HashMap implements Externalizable
entry=_suffixMap.getEntry(path,i+1,l-i-1);
if (entry!=null)
return (Entry) entry.getValue();
- }
-
+ }
+
// Default
return _default;
}
-
+
/* --------------------------------------------------------------- */
/** Get all entries matched by the path.
* Best match first.
@@ -263,20 +263,20 @@ public class PathMap extends HashMap implements Externalizable
* @return LazyList of Map.Entry instances key=pathSpec
*/
public Object getLazyMatches(String path)
- {
+ {
Map.Entry entry;
Object entries=null;
if (path==null)
return LazyList.getList(entries);
-
+
int l=path.length();
// try exact match
entry=_exactMap.getEntry(path,0,l);
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
-
+
// prefix search
int i=l-1;
while((i=path.lastIndexOf('/',i-1))>=0)
@@ -285,11 +285,11 @@ public class PathMap extends HashMap implements Externalizable
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
}
-
+
// Prefix Default
if (_prefixDefault!=null)
entries=LazyList.add(entries,_prefixDefault);
-
+
// Extension search
i=0;
while ((i=path.indexOf('.',i+1))>0)
@@ -305,13 +305,13 @@ public class PathMap extends HashMap implements Externalizable
// Optimization for just the default
if (entries==null)
return _defaultSingletonList;
-
+
entries=LazyList.add(entries,_default);
}
-
+
return entries;
}
-
+
/* --------------------------------------------------------------- */
/** Get all entries matched by the path.
* Best match first.
@@ -319,7 +319,7 @@ public class PathMap extends HashMap implements Externalizable
* @return List of Map.Entry instances key=pathSpec
*/
public List getMatches(String path)
- {
+ {
return LazyList.getList(getLazyMatches(path));
}
@@ -330,12 +330,12 @@ public class PathMap extends HashMap implements Externalizable
* @return Whether the PathMap contains any entries that match this
*/
public boolean containsMatch(String path)
- {
+ {
Entry match = getMatch(path);
return match!=null && !match.equals(_default);
}
- /* --------------------------------------------------------------- */
+ /* --------------------------------------------------------------- */
@Override
public Object remove(Object pathSpec)
{
@@ -362,7 +362,7 @@ public class PathMap extends HashMap implements Externalizable
}
return super.remove(pathSpec);
}
-
+
/* --------------------------------------------------------------- */
@Override
public void clear()
@@ -374,7 +374,7 @@ public class PathMap extends HashMap implements Externalizable
_defaultSingletonList=null;
super.clear();
}
-
+
/* --------------------------------------------------------------- */
/**
* @return true if match.
@@ -397,7 +397,7 @@ public class PathMap extends HashMap implements Externalizable
{
if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path))
return true;
-
+
if(isPathWildcardMatch(pathSpec, path))
return true;
}
@@ -419,24 +419,24 @@ public class PathMap extends HashMap implements Externalizable
}
return false;
}
-
-
+
+
/* --------------------------------------------------------------- */
/** Return the portion of a path that matches a path spec.
* @return null if no match at all.
*/
public static String pathMatch(String pathSpec, String path)
- {
+ {
char c = pathSpec.charAt(0);
-
+
if (c=='/')
{
if (pathSpec.length()==1)
return path;
-
+
if (pathSpec.equals(path))
return path;
-
+
if (isPathWildcardMatch(pathSpec, path))
return path.substring(0,pathSpec.length()-2);
}
@@ -448,7 +448,7 @@ public class PathMap extends HashMap implements Externalizable
}
return null;
}
-
+
/* --------------------------------------------------------------- */
/** Return the portion of a path that is after a path spec.
* @return The path info string
@@ -456,12 +456,12 @@ public class PathMap extends HashMap implements Externalizable
public static String pathInfo(String pathSpec, String path)
{
char c = pathSpec.charAt(0);
-
+
if (c=='/')
{
if (pathSpec.length()==1)
return null;
-
+
boolean wildcard = isPathWildcardMatch(pathSpec, path);
// handle the case where pathSpec uses a wildcard and path info is "/*"
@@ -474,7 +474,7 @@ public class PathMap extends HashMap implements Externalizable
return null;
return path.substring(pathSpec.length()-2);
}
- }
+ }
return null;
}
@@ -484,7 +484,7 @@ public class PathMap extends HashMap implements Externalizable
* @param base The base the path is relative to.
* @param pathSpec The spec of the path segment to ignore.
* @param path the additional path
- * @return base plus path with pathspec removed
+ * @return base plus path with pathspec removed
*/
public static String relativePath(String base,
String pathSpec,
@@ -508,7 +508,7 @@ public class PathMap extends HashMap implements Externalizable
path = base + URIUtil.SLASH + info;
return path;
}
-
+
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@@ -516,7 +516,7 @@ public class PathMap extends HashMap implements Externalizable
{
private final Object key;
private final Object value;
- private String mapped;
+ private String mapped;
private transient String string;
Entry(Object key, Object value)
@@ -529,7 +529,7 @@ public class PathMap extends HashMap implements Externalizable
{
return key;
}
-
+
public Object getValue()
{
return value;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslContextFactory.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslContextFactory.java
index 52cecaaad1b..90227c88073 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslContextFactory.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslContextFactory.java
@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.InetAddress;
import java.security.InvalidParameterException;
import java.security.KeyStore;
import java.security.SecureRandom;
@@ -42,7 +43,10 @@ import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
@@ -51,6 +55,8 @@ import javax.net.ssl.X509TrustManager;
import org.eclipse.jetty.http.security.Password;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.CertificateUtils;
import org.eclipse.jetty.util.security.CertificateValidator;
@@ -65,6 +71,8 @@ import org.eclipse.jetty.util.security.CertificateValidator;
*/
public class SslContextFactory extends AbstractLifeCycle
{
+ private static final Logger LOG = Log.getLogger(SslContextFactory.class);
+
public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
(Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
"SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
@@ -82,8 +90,14 @@ public class SslContextFactory extends AbstractLifeCycle
/** String name of keystore password property. */
public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
+ /** Excluded protocols. */
+ private final Set _excludeProtocols = new HashSet();
+ // private final Set _excludeProtocols = new HashSet(Collections.singleton("SSLv2Hello"));
+ /** Included protocols. */
+ private Set _includeProtocols = null;
+
/** Excluded cipher suites. */
- private Set _excludeCipherSuites = null;
+ private final Set _excludeCipherSuites = new HashSet();
/** Included cipher suites. */
private Set _includeCipherSuites = null;
@@ -196,6 +210,7 @@ public class SslContextFactory extends AbstractLifeCycle
if (_keyStoreInputStream == null && _keyStorePath == null &&
_trustStoreInputStream == null && _trustStorePath == null )
{
+ LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
// Create a trust manager that does not validate certificate chains
TrustManager trustAllCerts = new X509TrustManager()
{
@@ -218,11 +233,115 @@ public class SslContextFactory extends AbstractLifeCycle
}
else
{
- createSSLContext();
+ // verify that keystore and truststore
+ // parameters are set up correctly
+ try
+ {
+ checkKeyStore();
+ }
+ catch(IllegalStateException e)
+ {
+ LOG.ignore(e);
+ }
+
+ KeyStore keyStore = loadKeyStore();
+ KeyStore trustStore = loadTrustStore();
+
+ Collection extends CRL> crls = loadCRL(_crlPath);
+
+ if (_validateCerts && keyStore != null)
+ {
+ if (_certAlias == null)
+ {
+ List aliases = Collections.list(keyStore.aliases());
+ _certAlias = aliases.size() == 1 ? aliases.get(0) : null;
+ }
+
+ Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
+ if (cert == null)
+ {
+ throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
+ }
+
+ CertificateValidator validator = new CertificateValidator(trustStore, crls);
+ validator.setMaxCertPathLength(_maxCertPathLength);
+ validator.setEnableCRLDP(_enableCRLDP);
+ validator.setEnableOCSP(_enableOCSP);
+ validator.setOcspResponderURL(_ocspResponderURL);
+ validator.validate(keyStore, cert);
+ }
+
+ KeyManager[] keyManagers = getKeyManagers(keyStore);
+ TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
+
+ SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
+ _context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
+ _context.init(keyManagers,trustManagers,secureRandom);
+
+ SSLEngine engine=newSslEngine();
+ LOG.info("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
+ LOG.debug("Enabled Ciphers {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
}
}
}
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The array of protocol names to exclude from
+ * {@link SSLEngine#setEnabledProtocols(String[])}
+ */
+ public String[] getExcludeProtocols()
+ {
+ return _excludeProtocols.toArray(new String[_excludeProtocols.size()]);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param Protocols
+ * The array of protocol names to exclude from
+ * {@link SSLEngine#setEnabledProtocols(String[])}
+ */
+ public void setExcludeProtocols(String... protocols)
+ {
+ checkNotStarted();
+
+ _excludeProtocols.clear();
+ _excludeProtocols.addAll(Arrays.asList(protocols));
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param protocol Protocol names to add to {@link SSLEngine#setEnabledProtocols(String[])}
+ */
+ public void addExcludeProtocols(String... protocol)
+ {
+ checkNotStarted();
+ _excludeProtocols.addAll(Arrays.asList(protocol));
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return The array of protocol names to include in
+ * {@link SSLEngine#setEnabledProtocols(String[])}
+ */
+ public String[] getIncludeProtocols()
+ {
+ return _includeProtocols.toArray(new String[_includeProtocols.size()]);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param Protocols
+ * The array of protocol names to include in
+ * {@link SSLEngine#setEnabledProtocols(String[])}
+ */
+ public void setIncludeProtocols(String... protocols)
+ {
+ checkNotStarted();
+
+ _includeProtocols = new HashSet(Arrays.asList(protocols));
+ }
+
/* ------------------------------------------------------------ */
/**
* @return The array of cipher suite names to exclude from
@@ -239,11 +358,21 @@ public class SslContextFactory extends AbstractLifeCycle
* The array of cipher suite names to exclude from
* {@link SSLEngine#setEnabledCipherSuites(String[])}
*/
- public void setExcludeCipherSuites(String[] cipherSuites)
+ public void setExcludeCipherSuites(String... cipherSuites)
{
- checkStarted();
-
- _excludeCipherSuites = new HashSet(Arrays.asList(cipherSuites));
+ checkNotStarted();
+ _excludeCipherSuites.clear();
+ _excludeCipherSuites.addAll(Arrays.asList(cipherSuites));
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param cipher Cipher names to add to {@link SSLEngine#setEnabledCipherSuites(String[])}
+ */
+ public void addExcludeCipherSuites(String... cipher)
+ {
+ checkNotStarted();
+ _excludeCipherSuites.addAll(Arrays.asList(cipher));
}
/* ------------------------------------------------------------ */
@@ -262,9 +391,9 @@ public class SslContextFactory extends AbstractLifeCycle
* The array of cipher suite names to include in
* {@link SSLEngine#setEnabledCipherSuites(String[])}
*/
- public void setIncludeCipherSuites(String[] cipherSuites)
+ public void setIncludeCipherSuites(String... cipherSuites)
{
- checkStarted();
+ checkNotStarted();
_includeCipherSuites = new HashSet(Arrays.asList(cipherSuites));
}
@@ -285,7 +414,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStore(String keyStorePath)
{
- checkStarted();
+ checkNotStarted();
_keyStorePath = keyStorePath;
}
@@ -306,7 +435,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreProvider(String keyStoreProvider)
{
- checkStarted();
+ checkNotStarted();
_keyStoreProvider = keyStoreProvider;
}
@@ -327,7 +456,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreType(String keyStoreType)
{
- checkStarted();
+ checkNotStarted();
_keyStoreType = keyStoreType;
}
@@ -341,7 +470,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public InputStream getKeyStoreInputStream()
{
- checkConfig();
+ checkKeyStore();
return _keyStoreInputStream;
}
@@ -355,7 +484,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
{
- checkStarted();
+ checkNotStarted();
_keyStoreInputStream = keyStoreInputStream;
}
@@ -376,7 +505,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setCertAlias(String certAlias)
{
- checkStarted();
+ checkNotStarted();
_certAlias = certAlias;
}
@@ -397,7 +526,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(String trustStorePath)
{
- checkStarted();
+ checkNotStarted();
_trustStorePath = trustStorePath;
}
@@ -418,7 +547,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStoreProvider(String trustStoreProvider)
{
- checkStarted();
+ checkNotStarted();
_trustStoreProvider = trustStoreProvider;
}
@@ -439,7 +568,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStoreType(String trustStoreType)
{
- checkStarted();
+ checkNotStarted();
_trustStoreType = trustStoreType;
}
@@ -453,7 +582,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public InputStream getTrustStoreInputStream()
{
- checkConfig();
+ checkKeyStore();
return _trustStoreInputStream;
}
@@ -467,7 +596,7 @@ public class SslContextFactory extends AbstractLifeCycle
@Deprecated
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
{
- checkStarted();
+ checkNotStarted();
_trustStoreInputStream = trustStoreInputStream;
}
@@ -490,7 +619,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setNeedClientAuth(boolean needClientAuth)
{
- checkStarted();
+ checkNotStarted();
_needClientAuth = needClientAuth;
}
@@ -513,7 +642,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setWantClientAuth(boolean wantClientAuth)
{
- checkStarted();
+ checkNotStarted();
_wantClientAuth = wantClientAuth;
}
@@ -545,7 +674,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setValidateCerts(boolean validateCerts)
{
- checkStarted();
+ checkNotStarted();
_validateCerts = validateCerts;
}
@@ -566,7 +695,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setValidatePeerCerts(boolean validatePeerCerts)
{
- checkStarted();
+ checkNotStarted();
_validatePeerCerts = validatePeerCerts;
}
@@ -593,7 +722,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setAllowRenegotiate(boolean allowRenegotiate)
{
- checkStarted();
+ checkNotStarted();
_allowRenegotiate = allowRenegotiate;
}
@@ -605,7 +734,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStorePassword(String password)
{
- checkStarted();
+ checkNotStarted();
_keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
}
@@ -617,7 +746,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyManagerPassword(String password)
{
- checkStarted();
+ checkNotStarted();
_keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
}
@@ -629,7 +758,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStorePassword(String password)
{
- checkStarted();
+ checkNotStarted();
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
}
@@ -652,7 +781,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setProvider(String provider)
{
- checkStarted();
+ checkNotStarted();
_sslProvider = provider;
}
@@ -675,7 +804,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setProtocol(String protocol)
{
- checkStarted();
+ checkNotStarted();
_sslProtocol = protocol;
}
@@ -700,7 +829,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSecureRandomAlgorithm(String algorithm)
{
- checkStarted();
+ checkNotStarted();
_secureRandomAlgorithm = algorithm;
}
@@ -721,7 +850,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
{
- checkStarted();
+ checkNotStarted();
_keyManagerFactoryAlgorithm = algorithm;
}
@@ -742,7 +871,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustManagerFactoryAlgorithm(String algorithm)
{
- checkStarted();
+ checkNotStarted();
_trustManagerFactoryAlgorithm = algorithm;
}
@@ -763,7 +892,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setCrlPath(String crlPath)
{
- checkStarted();
+ checkNotStarted();
_crlPath = crlPath;
}
@@ -786,7 +915,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setMaxCertPathLength(int maxCertPathLength)
{
- checkStarted();
+ checkNotStarted();
_maxCertPathLength = maxCertPathLength;
}
@@ -797,6 +926,8 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public SSLContext getSslContext()
{
+ if (!isStarted())
+ throw new IllegalStateException(getState());
return _context;
}
@@ -807,60 +938,11 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setSslContext(SSLContext sslContext)
{
- checkStarted();
+ checkNotStarted();
_context = sslContext;
}
- /* ------------------------------------------------------------ */
- /**
- * @throws Exception
- */
- protected void createSSLContext() throws Exception
- {
- // verify that keystore and truststore
- // parameters are set up correctly
- checkConfig();
-
- KeyStore keyStore = loadKeyStore();
- KeyStore trustStore = loadTrustStore();
-
- Collection extends CRL> crls = loadCRL(_crlPath);
-
- if (_validateCerts && keyStore != null)
- {
- if (_certAlias == null)
- {
- List aliases = Collections.list(keyStore.aliases());
- _certAlias = aliases.size() == 1 ? aliases.get(0) : null;
- }
-
- Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
- if (cert == null)
- {
- throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
- }
-
- CertificateValidator validator = new CertificateValidator(trustStore, crls);
- validator.setMaxCertPathLength(_maxCertPathLength);
- validator.setEnableCRLDP(_enableCRLDP);
- validator.setEnableOCSP(_enableOCSP);
- validator.setOcspResponderURL(_ocspResponderURL);
- validator.validate(keyStore, cert);
- }
-
- KeyManager[] keyManagers = getKeyManagers(keyStore);
- TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
-
- SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
- _context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
- _context.init(keyManagers,trustManagers,secureRandom);
-
- SSLSessionContext sslSessionContext = _context.getServerSessionContext();
- sslSessionContext.setSessionCacheSize(_sslSessionCacheSize);
- sslSessionContext.setSessionTimeout(_sslSessionTimeout);
- }
-
/* ------------------------------------------------------------ */
/**
* Override this method to provide alternate way to load a keystore.
@@ -1014,33 +1096,27 @@ public class SslContextFactory extends AbstractLifeCycle
/* ------------------------------------------------------------ */
/**
- * Check configuration. Ensures that if keystore has been
+ * Check KetyStore Configuration. Ensures that if keystore has been
* configured but there's no truststore, that keystore is
* used as truststore.
- * @return true SslContextFactory configuration can be used in server connector.
+ * @throws IllegalStateException if SslContextFactory configuration can't be used.
*/
- public boolean checkConfig()
+ public void checkKeyStore()
{
- boolean check = true;
if (_keyStore == null && _keyStoreInputStream == null && _keyStorePath == null)
+ throw new IllegalStateException("SSL doesn't have a valid keystore");
+
+ // if the keystore has been configured but there is no
+ // truststore configured, use the keystore as the truststore
+ if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
{
- // configuration doesn't have a valid keystore
- check = false;
- }
- else
- {
- // if the keystore has been configured but there is no
- // truststore configured, use the keystore as the truststore
- if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
- {
- _trustStore = _keyStore;
- _trustStorePath = _keyStorePath;
- _trustStoreInputStream = _keyStoreInputStream;
- _trustStoreType = _keyStoreType;
- _trustStoreProvider = _keyStoreProvider;
- _trustStorePassword = _keyStorePassword;
- _trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
- }
+ _trustStore = _keyStore;
+ _trustStorePath = _keyStorePath;
+ _trustStoreInputStream = _keyStoreInputStream;
+ _trustStoreType = _keyStoreType;
+ _trustStoreProvider = _keyStoreProvider;
+ _trustStorePassword = _keyStorePassword;
+ _trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
}
// It's the same stream we cannot read it twice, so read it once in memory
@@ -1057,11 +1133,9 @@ public class SslContextFactory extends AbstractLifeCycle
}
catch (Exception ex)
{
- throw new RuntimeException(ex);
+ throw new IllegalStateException(ex);
}
}
-
- return check;
}
/* ------------------------------------------------------------ */
@@ -1073,57 +1147,68 @@ public class SslContextFactory extends AbstractLifeCycle
* @param supportedCipherSuites Array of supported cipher suites
* @return Array of cipher suites to enable
*/
- public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
+ public String[] selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
{
- Set selectedCipherSuites = null;
- if (enabledCipherSuites != null)
+ Set selected_protocols = new HashSet();
+
+ // Set the starting protocols - either from the included or enabled list
+ if (_includeProtocols!=null)
{
- selectedCipherSuites = new HashSet(Arrays.asList(enabledCipherSuites));
+ // Use only the supported included protocols
+ for (String protocol : supportedProtocols)
+ if (_includeProtocols.contains(protocol))
+ selected_protocols.add(protocol);
}
else
+ selected_protocols.addAll(Arrays.asList(enabledProtocols));
+
+
+ // Remove any excluded protocols
+ if (_excludeProtocols != null)
+ selected_protocols.removeAll(_excludeProtocols);
+
+ return selected_protocols.toArray(new String[selected_protocols.size()]);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Select cipher suites to be used by the connector
+ * based on configured inclusion and exclusion lists
+ * as well as enabled and supported cipher suite lists.
+ * @param enabledCipherSuites Array of enabled cipher suites
+ * @param supportedCipherSuites Array of supported cipher suites
+ * @return Array of cipher suites to enable
+ */
+ public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
+ {
+ Set selected_ciphers = new HashSet();
+
+ // Set the starting ciphers - either from the included or enabled list
+ if (_includeCipherSuites!=null)
{
- selectedCipherSuites = new HashSet();
+ // Use only the supported included ciphers
+ for (String cipherSuite : supportedCipherSuites)
+ if (_includeCipherSuites.contains(cipherSuite))
+ selected_ciphers.add(cipherSuite);
}
-
- if ((supportedCipherSuites != null && supportedCipherSuites.length > 0) &&
- (_includeCipherSuites != null && _includeCipherSuites.size() > 0))
- {
- Set supportedCSList = new HashSet(Arrays.asList(supportedCipherSuites));
-
- for (String cipherName : _includeCipherSuites)
- {
- if ((!selectedCipherSuites.contains(cipherName)) &&
- supportedCSList.contains(cipherName))
- {
- selectedCipherSuites.add(cipherName);
- }
- }
- }
-
- if (_excludeCipherSuites != null && _excludeCipherSuites.size() > 0)
- {
- for (String cipherName : _excludeCipherSuites)
- {
- if (selectedCipherSuites.contains(cipherName))
- {
- selectedCipherSuites.remove(cipherName);
- }
- }
- }
-
- return selectedCipherSuites.toArray(new String[selectedCipherSuites.size()]);
+ else
+ selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
+
+
+ // Remove any excluded ciphers
+ if (_excludeCipherSuites != null)
+ selected_ciphers.removeAll(_excludeCipherSuites);
+ return selected_ciphers.toArray(new String[selected_ciphers.size()]);
}
/* ------------------------------------------------------------ */
/**
* Check if the lifecycle has been started and throw runtime exception
*/
- protected void checkStarted()
+ protected void checkNotStarted()
{
if (isStarted())
- {
- throw new IllegalStateException("Cannot modify configuration after SslContextFactory was started");
- }
+ throw new IllegalStateException("Cannot modify configuration when "+getState());
}
/* ------------------------------------------------------------ */
@@ -1141,7 +1226,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setEnableCRLDP(boolean enableCRLDP)
{
- checkStarted();
+ checkNotStarted();
_enableCRLDP = enableCRLDP;
}
@@ -1161,7 +1246,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setEnableOCSP(boolean enableOCSP)
{
- checkStarted();
+ checkNotStarted();
_enableOCSP = enableOCSP;
}
@@ -1181,7 +1266,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setOcspResponderURL(String ocspResponderURL)
{
- checkStarted();
+ checkNotStarted();
_ocspResponderURL = ocspResponderURL;
}
@@ -1192,7 +1277,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStore(KeyStore keyStore)
{
- checkStarted();
+ checkNotStarted();
_keyStore = keyStore;
}
@@ -1203,7 +1288,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(KeyStore trustStore)
{
- checkStarted();
+ checkNotStarted();
_trustStore = trustStore;
}
@@ -1214,7 +1299,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setKeyStoreResource(Resource resource)
{
- checkStarted();
+ checkNotStarted();
try
{
@@ -1233,7 +1318,7 @@ public class SslContextFactory extends AbstractLifeCycle
*/
public void setTrustStore(Resource resource)
{
- checkStarted();
+ checkNotStarted();
try
{
@@ -1299,4 +1384,83 @@ public class SslContextFactory extends AbstractLifeCycle
{
_sslSessionTimeout = sslSessionTimeout;
}
+
+
+ /* ------------------------------------------------------------ */
+ public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException
+ {
+ SSLServerSocketFactory factory = _context.getServerSocketFactory();
+
+ SSLServerSocket socket =
+ (SSLServerSocket) (host==null ?
+ factory.createServerSocket(port,backlog):
+ factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
+
+ if (getWantClientAuth())
+ socket.setWantClientAuth(getWantClientAuth());
+ if (getNeedClientAuth())
+ socket.setNeedClientAuth(getNeedClientAuth());
+
+ socket.setEnabledCipherSuites(selectCipherSuites(
+ socket.getEnabledCipherSuites(),
+ socket.getSupportedCipherSuites()));
+ socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
+
+ return socket;
+ }
+
+ /* ------------------------------------------------------------ */
+ public SSLSocket newSslSocket() throws IOException
+ {
+ SSLSocketFactory factory = _context.getSocketFactory();
+
+ SSLSocket socket = (SSLSocket)factory.createSocket();
+
+ if (getWantClientAuth())
+ socket.setWantClientAuth(getWantClientAuth());
+ if (getNeedClientAuth())
+ socket.setNeedClientAuth(getNeedClientAuth());
+
+ socket.setEnabledCipherSuites(selectCipherSuites(
+ socket.getEnabledCipherSuites(),
+ socket.getSupportedCipherSuites()));
+ socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
+
+ return socket;
+ }
+
+ /* ------------------------------------------------------------ */
+ public SSLEngine newSslEngine(String host,int port)
+ {
+ SSLEngine sslEngine=isSessionCachingEnabled()
+ ?_context.createSSLEngine(host, port)
+ :_context.createSSLEngine();
+
+ customize(sslEngine);
+ return sslEngine;
+ }
+
+ /* ------------------------------------------------------------ */
+ public SSLEngine newSslEngine()
+ {
+ SSLEngine sslEngine=_context.createSSLEngine();
+ customize(sslEngine);
+ return sslEngine;
+ }
+
+ /* ------------------------------------------------------------ */
+ public void customize(SSLEngine sslEngine)
+ {
+ if (getWantClientAuth())
+ sslEngine.setWantClientAuth(getWantClientAuth());
+ if (getNeedClientAuth())
+ sslEngine.setNeedClientAuth(getNeedClientAuth());
+
+ sslEngine.setEnabledCipherSuites(selectCipherSuites(
+ sslEngine.getEnabledCipherSuites(),
+ sslEngine.getSupportedCipherSuites()));
+
+ sslEngine.setEnabledProtocols(selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols()));
+ }
+
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
index 21919c5fe12..6940991f387 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
@@ -47,6 +47,7 @@ public interface EndPoint
* The buffer may chose to do a compact before filling.
* @return an int 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;
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java
index e9e7d5e00ca..f749f0ba417 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java
@@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
-// The Eclipse Public License is available at
+// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
-// You may elect to redistribute this code under either of these licenses.
+// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.bio;
@@ -17,6 +17,7 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
+import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
@@ -34,13 +35,13 @@ public class SocketEndPoint extends StreamEndPoint
final Socket _socket;
final InetSocketAddress _local;
final InetSocketAddress _remote;
-
+
/* ------------------------------------------------------------ */
/**
- *
+ *
*/
public SocketEndPoint(Socket socket)
- throws IOException
+ throws IOException
{
super(socket.getInputStream(),socket.getOutputStream());
_socket=socket;
@@ -48,13 +49,13 @@ public class SocketEndPoint extends StreamEndPoint
_remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
super.setMaxIdleTime(_socket.getSoTimeout());
}
-
+
/* ------------------------------------------------------------ */
/**
- *
+ *
*/
protected SocketEndPoint(Socket socket, int maxIdleTime)
- throws IOException
+ throws IOException
{
super(socket.getInputStream(),socket.getOutputStream());
_socket=socket;
@@ -63,7 +64,7 @@ public class SocketEndPoint extends StreamEndPoint
_socket.setSoTimeout(maxIdleTime>0?maxIdleTime:0);
super.setMaxIdleTime(maxIdleTime);
}
-
+
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#isClosed()
@@ -73,19 +74,19 @@ public class SocketEndPoint extends StreamEndPoint
{
return super.isOpen() && _socket!=null && !_socket.isClosed();
}
-
+
/* ------------------------------------------------------------ */
@Override
public boolean isInputShutdown()
{
- return !super.isOpen() || _socket!=null && _socket.isInputShutdown();
+ return !isOpen() || super.isInputShutdown();
}
-
+
/* ------------------------------------------------------------ */
@Override
public boolean isOutputShutdown()
{
- return !super.isOpen() || _socket!=null && _socket.isOutputShutdown();
+ return !isOpen() || super.isOutputShutdown();
}
/* ------------------------------------------------------------ */
@@ -94,9 +95,13 @@ public class SocketEndPoint extends StreamEndPoint
*/
@Override
public void shutdownOutput() throws IOException
- {
- if (!_socket.isClosed() && !_socket.isOutputShutdown())
- _socket.shutdownOutput();
+ {
+ if (!isOutputShutdown())
+ {
+ super.shutdownOutput();
+ if (!(_socket instanceof SSLSocket))
+ _socket.shutdownOutput();
+ }
}
@@ -106,11 +111,15 @@ public class SocketEndPoint extends StreamEndPoint
*/
@Override
public void shutdownInput() throws IOException
- {
- if (!_socket.isClosed() && !_socket.isInputShutdown())
- _socket.shutdownInput();
+ {
+ if (!isInputShutdown())
+ {
+ super.shutdownInput();
+ if (!(_socket instanceof SSLSocket))
+ _socket.shutdownInput();
+ }
}
-
+
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#close()
@@ -122,10 +131,10 @@ public class SocketEndPoint extends StreamEndPoint
_in=null;
_out=null;
}
-
+
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getLocalAddr()
*/
@Override
@@ -133,12 +142,12 @@ public class SocketEndPoint extends StreamEndPoint
{
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
return StringUtil.ALL_INTERFACES;
-
+
return _local.getAddress().getHostAddress();
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getLocalHost()
*/
@Override
@@ -146,12 +155,12 @@ public class SocketEndPoint extends StreamEndPoint
{
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
return StringUtil.ALL_INTERFACES;
-
+
return _local.getAddress().getCanonicalHostName();
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getLocalPort()
*/
@Override
@@ -163,7 +172,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getRemoteAddr()
*/
@Override
@@ -176,7 +185,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getRemoteHost()
*/
@Override
@@ -188,7 +197,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getRemotePort()
*/
@Override
@@ -200,7 +209,7 @@ public class SocketEndPoint extends StreamEndPoint
}
/* ------------------------------------------------------------ */
- /*
+ /*
* @see org.eclipse.io.EndPoint#getConnection()
*/
@Override
@@ -237,5 +246,5 @@ public class SocketEndPoint extends StreamEndPoint
_socket.close();
}
}
-
+
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java
index fde7272eb77..da1f58b007f 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java
@@ -22,17 +22,13 @@ import java.net.SocketTimeoutException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.EndPoint;
-/**
- *
- *
- * To change the template for this generated type comment go to
- * Window - Preferences - Java - Code Generation - Code and Comments
- */
public class StreamEndPoint implements EndPoint
{
InputStream _in;
OutputStream _out;
int _maxIdleTime;
+ boolean _ishut;
+ boolean _oshut;
/**
*
@@ -75,23 +71,33 @@ public class StreamEndPoint implements EndPoint
}
public void shutdownOutput() throws IOException
- {
+ {
+ if (_oshut)
+ return;
+ _oshut = true;
+ if (_out!=null)
+ _out.close();
}
-
+
public boolean isInputShutdown()
{
- return !isOpen();
+ return _ishut;
}
public void shutdownInput() throws IOException
- {
+ {
+ if (_ishut)
+ return;
+ _ishut = true;
+ if (_in!=null)
+ _in.close();
}
-
+
public boolean isOutputShutdown()
{
- return !isOpen();
+ return _oshut;
}
-
+
/*
* @see org.eclipse.io.BufferIO#close()
*/
@@ -107,35 +113,43 @@ public class StreamEndPoint implements EndPoint
protected void idleExpired() throws IOException
{
- _in.close();
+ if (_in!=null)
+ _in.close();
}
-
+
/* (non-Javadoc)
* @see org.eclipse.io.BufferIO#fill(org.eclipse.io.Buffer)
*/
public int fill(Buffer buffer) throws IOException
{
- // TODO handle null array()
if (_in==null)
return 0;
- int space=buffer.space();
- if (space<=0)
- {
- if (buffer.hasContent())
- return 0;
- throw new IOException("FULL");
- }
+ int space=buffer.space();
+ if (space<=0)
+ {
+ if (buffer.hasContent())
+ return 0;
+ throw new IOException("FULL");
+ }
- try
- {
- return buffer.readFrom(_in,space);
- }
- catch(SocketTimeoutException e)
- {
- idleExpired();
- return -1;
- }
+ try
+ {
+ int read=buffer.readFrom(_in, space);
+ if (read<0 && isOpen())
+ {
+ if (!isInputShutdown())
+ shutdownInput();
+ else if (isOutputShutdown())
+ close();
+ }
+ return read;
+ }
+ catch(SocketTimeoutException e)
+ {
+ idleExpired();
+ return -1;
+ }
}
/* (non-Javadoc)
@@ -143,7 +157,6 @@ public class StreamEndPoint implements EndPoint
*/
public int flush(Buffer buffer) throws IOException
{
- // TODO handle null array()
if (_out==null)
return -1;
int length=buffer.length();
@@ -313,13 +326,13 @@ public class StreamEndPoint implements EndPoint
{
return false;
}
-
+
/* ------------------------------------------------------------ */
public int getMaxIdleTime()
{
return _maxIdleTime;
}
-
+
/* ------------------------------------------------------------ */
public void setMaxIdleTime(int timeMs) throws IOException
{
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java
index 839996dbb52..9670613eede 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java
@@ -109,9 +109,12 @@ public class ChannelEndPoint implements EndPoint
if (_channel.isOpen() && _channel instanceof SocketChannel)
{
Socket socket= ((SocketChannel)_channel).socket();
- if (!socket.isClosed()&&!socket.isInputShutdown())
+ if (!socket.isClosed())
{
- socket.shutdownInput();
+ if(socket.isOutputShutdown())
+ socket.close();
+ else if (!socket.isInputShutdown())
+ socket.shutdownInput();
}
}
}
@@ -124,9 +127,12 @@ public class ChannelEndPoint implements EndPoint
if (_channel.isOpen() && _channel instanceof SocketChannel)
{
Socket socket= ((SocketChannel)_channel).socket();
- if (!socket.isClosed()&&!socket.isOutputShutdown())
+ if (!socket.isClosed())
{
- socket.shutdownOutput();
+ if (socket.isInputShutdown())
+ socket.close();
+ else if (!socket.isOutputShutdown())
+ socket.shutdownOutput();
}
}
}
@@ -160,8 +166,8 @@ public class ChannelEndPoint implements EndPoint
{
final NIOBuffer nbuf = (NIOBuffer)buf;
final ByteBuffer bbuf=nbuf.getByteBuffer();
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
+ //noinspection SynchronizationOnLocalVariableOrMethodParameter
try
{
synchronized(bbuf)
@@ -178,13 +184,17 @@ public class ChannelEndPoint implements EndPoint
}
}
- if (len<0 && isOpen() && !isInputShutdown())
+ if (len<0 && isOpen())
{
- shutdownInput();
+ if (!isInputShutdown())
+ shutdownInput();
+ else if (isOutputShutdown())
+ _channel.close();
}
}
catch (IOException x)
{
+ LOG.debug(x);
try
{
close();
@@ -196,7 +206,6 @@ public class ChannelEndPoint implements EndPoint
if (len>0)
throw x;
- LOG.ignore(x);
len=-1;
}
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
index fd5413ff3e0..a318543f647 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java
@@ -34,27 +34,48 @@ import org.eclipse.jetty.util.log.Logger;
*/
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
{
- public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio");
+ public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
private final SelectorManager.SelectSet _selectSet;
private final SelectorManager _manager;
+ private SelectionKey _key;
private final Runnable _handler = new Runnable()
{
public void run() { handle(); }
};
+ /** The desired value for {@link SelectionKey#interestOps()} */
+ private int _interestOps;
+
+ /**
+ * The connection instance is the handler for any IO activity on the endpoint.
+ * There is a different type of connection for HTTP, AJP, WebSocket and
+ * ProxyConnect. The connection may change for an SCEP as it is upgraded
+ * from HTTP to proxy connect or websocket.
+ */
private volatile Connection _connection;
+
+ /** true if a thread has been dispatched to handle this endpoint */
private boolean _dispatched = false;
+
+ /** true if a non IO dispatch (eg async resume) is outstanding */
private boolean _redispatched = false;
+
+ /** true if the last write operation succeed and wrote all offered bytes */
private volatile boolean _writable = true;
- private SelectionKey _key;
- private int _interestOps;
+
+ /** True if a thread has is blocked in {@link #blockReadable(long)} */
private boolean _readBlocked;
- private boolean _writeBlocked;
- private boolean _open;
- private volatile long _idleTimestamp;
+ /** True if a thread has is blocked in {@link #blockWritable(long)} */
+ private boolean _writeBlocked;
+
+ /** true if {@link SelectSet#destroyEndPoint(SelectChannelEndPoint)} has not been called */
+ private boolean _open;
+
+ private volatile long _idleTimestamp;
+
/* ------------------------------------------------------------ */
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
throws IOException
@@ -90,6 +111,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
scheduleIdle();
}
+
/* ------------------------------------------------------------ */
public SelectionKey getSelectionKey()
{
@@ -205,7 +227,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
if(!dispatched)
{
_dispatched = false;
- __log.warn("Dispatched Failed! "+this+" to "+_manager);
+ LOG.warn("Dispatched Failed! "+this+" to "+_manager);
updateKey();
}
}
@@ -250,7 +272,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
public void checkIdleTimestamp(long now)
{
long idleTimestamp=_idleTimestamp;
- if (idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
+ if (!getChannel().isOpen() || idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
idleExpired();
}
@@ -260,6 +282,15 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_connection.idleExpired();
}
+ /* ------------------------------------------------------------ */
+ /**
+ * @return True if the endpoint has produced/consumed bytes itself (non application data).
+ */
+ public boolean isProgressing()
+ {
+ return false;
+ }
+
/* ------------------------------------------------------------ */
/*
*/
@@ -340,7 +371,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
- __log.warn(e);
+ LOG.warn(e);
}
finally
{
@@ -385,7 +416,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
- __log.warn(e);
+ LOG.warn(e);
}
finally
{
@@ -398,7 +429,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Throwable e)
{
// TODO remove this if it finds nothing
- __log.warn(e);
+ LOG.warn(e);
if (e instanceof RuntimeException)
throw (RuntimeException)e;
if (e instanceof Error)
@@ -414,10 +445,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
return true;
}
+
+ /* ------------------------------------------------------------ */
+ /* short cut for busyselectChannelServerTest */
+ public void clearWritable()
+ {
+ _writable=false;
+ }
/* ------------------------------------------------------------ */
public void scheduleWrite()
{
+ if (_writable==true)
+ LOG.debug("Required scheduleWrite {}",this);
+
_writable=false;
updateKey();
}
@@ -445,7 +486,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Exception e)
{
_key=null;
- __log.ignore(e);
+ LOG.ignore(e);
}
}
@@ -483,7 +524,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (Exception e)
{
- __log.ignore(e);
+ LOG.ignore(e);
if (_key!=null && _key.isValid())
{
_key.cancel();
@@ -520,9 +561,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
cancelIdle();
if (_open)
{
+ _open=false;
_selectSet.destroyEndPoint(this);
}
- _open=false;
_key = null;
}
}
@@ -545,7 +586,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
final Connection next = _connection.handle();
if (next!=_connection)
{
- __log.debug("{} replaced {}",next,_connection);
+ LOG.debug("{} replaced {}",next,_connection);
_connection=next;
continue;
}
@@ -554,26 +595,26 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (ClosedChannelException e)
{
- __log.ignore(e);
+ LOG.ignore(e);
}
catch (EofException e)
{
- __log.debug("EOF", e);
- try{close();}
- catch(IOException e2){__log.ignore(e2);}
+ LOG.debug("EOF", e);
+ try{getChannel().close();}
+ catch(IOException e2){LOG.ignore(e2);}
}
catch (IOException e)
{
- __log.warn(e.toString());
- __log.debug(e);
- try{close();}
- catch(IOException e2){__log.ignore(e2);}
+ LOG.warn(e.toString());
+ LOG.debug(e);
+ try{getChannel().close();}
+ catch(IOException e2){LOG.ignore(e2);}
}
catch (Throwable e)
{
- __log.warn("handle failed", e);
- try{close();}
- catch(IOException e2){__log.ignore(e2);}
+ LOG.warn("handle failed", e);
+ try{getChannel().close();}
+ catch(IOException e2){LOG.ignore(e2);}
}
dispatched=!undispatch();
}
@@ -585,7 +626,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
dispatched=!undispatch();
while (dispatched)
{
- __log.warn("SCEP.run() finally DISPATCHED");
+ LOG.warn("SCEP.run() finally DISPATCHED");
dispatched=!undispatch();
}
}
@@ -605,7 +646,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (IOException e)
{
- __log.ignore(e);
+ LOG.ignore(e);
}
finally
{
@@ -620,7 +661,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
synchronized(this)
{
return "SCEP@" + hashCode() + _channel+
- "[d=" + _dispatched + ",io=" + _interestOps+
+ "[o="+isOpen()+" d=" + _dispatched + ",io=" + _interestOps+
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
}
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java
index 5b80a68d9df..1b8218832a4 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java
@@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
-// The Eclipse Public License is available at
+// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
-// You may elect to redistribute this code under either of these licenses.
+// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.nio;
@@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
@@ -49,21 +48,16 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
* The Selector Manager manages and number of SelectSets to allow
* NIO scheduling to scale to large numbers of connections.
*
- * This class works around a number of know JVM bugs. For details
- * see http://wiki.eclipse.org/Jetty/Feature/JVM_NIO_Bug
*/
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
{
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
-
- // TODO Tune these by approx system speed.
- private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",0).intValue();
+
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
private static final int __MAX_SELECTS=Integer.getInteger("org.eclipse.jetty.io.nio.MAX_SELECTS",25000).intValue();
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
- private static final int __BUSY_KEY=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_KEY",-1).intValue();
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
-
+
private int _maxIdleTime;
private int _lowResourcesMaxIdleTime;
private long _lowResourcesConnections;
@@ -72,7 +66,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
private volatile int _set;
private boolean _deferringInterestedOps0=true;
private int _selectorPriorityDelta=0;
-
+
/* ------------------------------------------------------------ */
/**
* @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed.
@@ -82,18 +76,18 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_maxIdleTime=(int)maxIdleTime;
}
-
+
/* ------------------------------------------------------------ */
/**
* @param selectSets number of select sets to create
*/
public void setSelectSets(int selectSets)
{
- long lrc = _lowResourcesConnections * _selectSets;
+ long lrc = _lowResourcesConnections * _selectSets;
_selectSets=selectSets;
_lowResourcesConnections=lrc/_selectSets;
}
-
+
/* ------------------------------------------------------------ */
/**
* @return the max idle time
@@ -102,7 +96,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
return _maxIdleTime;
}
-
+
/* ------------------------------------------------------------ */
/**
* @return the number of select sets in use
@@ -114,14 +108,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/* ------------------------------------------------------------ */
/**
- * @param i
+ * @param i
* @return The select set
*/
public SelectSet getSelectSet(int i)
{
return _selectSet[i];
}
-
+
/* ------------------------------------------------------------ */
/** Register a channel
* @param channel
@@ -132,8 +126,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
// The ++ increment here is not atomic, but it does not matter.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
-
- int s=_set++;
+
+ int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
@@ -144,7 +138,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
}
-
+
/* ------------------------------------------------------------ */
/** Register a channel
* @param channel
@@ -154,8 +148,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
// The ++ increment here is not atomic, but it does not matter.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
-
- int s=_set++;
+
+ int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
@@ -165,14 +159,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
set.wakeup();
}
}
-
+
/* ------------------------------------------------------------ */
/** Register a {@link ServerSocketChannel}
* @param acceptChannel
*/
public void register(ServerSocketChannel acceptChannel)
{
- int s=_set++;
+ int s=_set++;
s=s%_selectSets;
SelectSet set=_selectSet[s];
set.addChange(acceptChannel);
@@ -196,8 +190,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_selectorPriorityDelta=delta;
}
-
-
+
+
/* ------------------------------------------------------------ */
/**
* @return the lowResourcesConnections
@@ -237,7 +231,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
}
-
+
/* ------------------------------------------------------------------------------- */
public abstract boolean dispatch(Runnable task);
@@ -254,7 +248,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
_selectSet[i]= new SelectSet(i);
super.doStart();
-
+
// start a thread to Select
for (int i=0;i _changes = new ConcurrentLinkedQueue