Merge branch 'jetty-9.1' into release-9.1
This commit is contained in:
commit
54726c67a7
|
@ -692,7 +692,6 @@ public class AnnotationParser
|
|||
parseDir(handlers, res, resolver);
|
||||
else
|
||||
{
|
||||
System.err.println("TRYING TO SCAN "+res);
|
||||
//we've already verified the directories, so just verify the class file name
|
||||
File file = res.getFile();
|
||||
if (isValidClassFileName((file==null?null:file.getName())))
|
||||
|
|
|
@ -40,12 +40,7 @@ public class AntWebInfConfiguration extends WebInfConfiguration
|
|||
|
||||
@Override
|
||||
public void preConfigure(final WebAppContext context) throws Exception
|
||||
{
|
||||
// Look for a work directory
|
||||
File work = findWorkDirectory(context);
|
||||
if (work != null)
|
||||
makeTempDirectory(work, context, false);
|
||||
|
||||
{
|
||||
//Make a temp directory for the webapp if one is not already set
|
||||
resolveTempDirectory(context);
|
||||
|
||||
|
|
|
@ -131,8 +131,7 @@ public class HttpConversation extends AttributesMap
|
|||
// will notify a listener that may send a new request and trigger
|
||||
// another call to this method which will build different listeners
|
||||
// which may be iterated over when the iteration continues.
|
||||
listeners = new ArrayList<>();
|
||||
|
||||
List<Response.ResponseListener> listeners = new ArrayList<>();
|
||||
HttpExchange firstExchange = exchanges.peekFirst();
|
||||
HttpExchange lastExchange = exchanges.peekLast();
|
||||
if (firstExchange == lastExchange)
|
||||
|
@ -151,6 +150,7 @@ public class HttpConversation extends AttributesMap
|
|||
else
|
||||
listeners.addAll(firstExchange.getResponseListeners());
|
||||
}
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
public void complete()
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
|
@ -296,93 +297,184 @@ public class HttpRequest implements Request
|
|||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestQueued(QueuedListener listener)
|
||||
public Request onRequestQueued(final QueuedListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new QueuedListener()
|
||||
{
|
||||
@Override
|
||||
public void onQueued(Request request)
|
||||
{
|
||||
listener.onQueued(request);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestBegin(BeginListener listener)
|
||||
public Request onRequestBegin(final BeginListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new BeginListener()
|
||||
{
|
||||
@Override
|
||||
public void onBegin(Request request)
|
||||
{
|
||||
listener.onBegin(request);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestHeaders(HeadersListener listener)
|
||||
public Request onRequestHeaders(final HeadersListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new HeadersListener()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
listener.onHeaders(request);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestCommit(CommitListener listener)
|
||||
public Request onRequestCommit(final CommitListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new CommitListener()
|
||||
{
|
||||
@Override
|
||||
public void onCommit(Request request)
|
||||
{
|
||||
listener.onCommit(request);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestContent(ContentListener listener)
|
||||
public Request onRequestContent(final ContentListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new ContentListener()
|
||||
{
|
||||
@Override
|
||||
public void onContent(Request request, ByteBuffer content)
|
||||
{
|
||||
listener.onContent(request, content);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestSuccess(SuccessListener listener)
|
||||
public Request onRequestSuccess(final SuccessListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new SuccessListener()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
listener.onSuccess(request);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onRequestFailure(FailureListener listener)
|
||||
public Request onRequestFailure(final FailureListener listener)
|
||||
{
|
||||
this.requestListeners.add(listener);
|
||||
this.requestListeners.add(new FailureListener()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Request request, Throwable failure)
|
||||
{
|
||||
listener.onFailure(request, failure);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseBegin(Response.BeginListener listener)
|
||||
public Request onResponseBegin(final Response.BeginListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.BeginListener()
|
||||
{
|
||||
@Override
|
||||
public void onBegin(Response response)
|
||||
{
|
||||
listener.onBegin(response);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseHeader(Response.HeaderListener listener)
|
||||
public Request onResponseHeader(final Response.HeaderListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.HeaderListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onHeader(Response response, HttpField field)
|
||||
{
|
||||
return listener.onHeader(response, field);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseHeaders(Response.HeadersListener listener)
|
||||
public Request onResponseHeaders(final Response.HeadersListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.HeadersListener()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
listener.onHeaders(response);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseContent(Response.ContentListener listener)
|
||||
public Request onResponseContent(final Response.ContentListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.ContentListener()
|
||||
{
|
||||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
listener.onContent(response, content);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseSuccess(Response.SuccessListener listener)
|
||||
public Request onResponseSuccess(final Response.SuccessListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.SuccessListener()
|
||||
{
|
||||
@Override
|
||||
public void onSuccess(Response response)
|
||||
{
|
||||
listener.onSuccess(response);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request onResponseFailure(Response.FailureListener listener)
|
||||
public Request onResponseFailure(final Response.FailureListener listener)
|
||||
{
|
||||
this.responseListeners.add(listener);
|
||||
this.responseListeners.add(new Response.FailureListener()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Response response, Throwable failure)
|
||||
{
|
||||
listener.onFailure(response, failure);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
||||
public abstract class PoolingHttpDestination<C extends Connection> extends HttpDestination implements Promise<Connection>
|
||||
{
|
||||
private final ConnectionPool connectionPool;
|
||||
|
||||
public PoolingHttpDestination(HttpClient client, Origin origin)
|
||||
{
|
||||
super(client, origin);
|
||||
this.connectionPool = newConnectionPool(client);
|
||||
}
|
||||
|
||||
protected ConnectionPool newConnectionPool(HttpClient client)
|
||||
{
|
||||
return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this);
|
||||
}
|
||||
|
||||
public ConnectionPool getConnectionPool()
|
||||
{
|
||||
return connectionPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void succeeded(Connection connection)
|
||||
{
|
||||
process((C)connection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Throwable x)
|
||||
{
|
||||
getHttpClient().getExecutor().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
abort(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void send()
|
||||
{
|
||||
C connection = acquire();
|
||||
if (connection != null)
|
||||
process(connection, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public C acquire()
|
||||
{
|
||||
return (C)connectionPool.acquire();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Processes a new connection making it idle or active depending on whether requests are waiting to be sent.</p>
|
||||
* <p>A new connection is created when a request needs to be executed; it is possible that the request that
|
||||
* triggered the request creation is executed by another connection that was just released, so the new connection
|
||||
* may become idle.</p>
|
||||
* <p>If a request is waiting to be executed, it will be dequeued and executed by the new connection.</p>
|
||||
*
|
||||
* @param connection the new connection
|
||||
* @param dispatch whether to dispatch the processing to another thread
|
||||
*/
|
||||
public void process(final C connection, boolean dispatch)
|
||||
{
|
||||
HttpClient client = getHttpClient();
|
||||
final HttpExchange exchange = getHttpExchanges().poll();
|
||||
LOG.debug("Processing exchange {} on connection {}", exchange, connection);
|
||||
if (exchange == null)
|
||||
{
|
||||
// TODO: review this part... may not be 100% correct
|
||||
// TODO: e.g. is client is not running, there should be no need to close the connection
|
||||
|
||||
if (!connectionPool.release(connection))
|
||||
connection.close();
|
||||
|
||||
if (!client.isRunning())
|
||||
{
|
||||
LOG.debug("{} is stopping", client);
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final Request request = exchange.getRequest();
|
||||
Throwable cause = request.getAbortCause();
|
||||
if (cause != null)
|
||||
{
|
||||
abort(exchange, cause);
|
||||
LOG.debug("Aborted before processing {}: {}", exchange, cause);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dispatch)
|
||||
{
|
||||
client.getExecutor().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
send(connection, exchange);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
send(connection, exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void send(C connection, HttpExchange exchange);
|
||||
|
||||
public void release(C connection)
|
||||
{
|
||||
LOG.debug("{} released", connection);
|
||||
HttpClient client = getHttpClient();
|
||||
if (client.isRunning())
|
||||
{
|
||||
if (connectionPool.isActive(connection))
|
||||
process(connection, false);
|
||||
else
|
||||
LOG.debug("{} explicit", connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("{} is stopped", client);
|
||||
close(connection);
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Connection oldConnection)
|
||||
{
|
||||
super.close(oldConnection);
|
||||
connectionPool.remove(oldConnection);
|
||||
|
||||
// We need to execute queued requests even if this connection failed.
|
||||
// We may create a connection that is not needed, but it will eventually
|
||||
// idle timeout, so no worries
|
||||
if (!getHttpExchanges().isEmpty())
|
||||
{
|
||||
C newConnection = acquire();
|
||||
if (newConnection != null)
|
||||
process(newConnection, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
connectionPool.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
ContainerLifeCycle.dump(out, indent, Arrays.asList(connectionPool));
|
||||
}
|
||||
}
|
|
@ -18,173 +18,21 @@
|
|||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jetty.client.ConnectionPool;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.client.PoolingHttpDestination;
|
||||
|
||||
public class HttpDestinationOverHTTP extends HttpDestination implements Promise<Connection>
|
||||
public class HttpDestinationOverHTTP extends PoolingHttpDestination<HttpConnectionOverHTTP>
|
||||
{
|
||||
private final ConnectionPool connectionPool;
|
||||
|
||||
public HttpDestinationOverHTTP(HttpClient client, Origin origin)
|
||||
{
|
||||
super(client, origin);
|
||||
this.connectionPool = newConnectionPool(client);
|
||||
}
|
||||
|
||||
protected ConnectionPool newConnectionPool(HttpClient client)
|
||||
{
|
||||
return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this);
|
||||
}
|
||||
|
||||
public ConnectionPool getConnectionPool()
|
||||
{
|
||||
return connectionPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded(Connection connection)
|
||||
protected void send(HttpConnectionOverHTTP connection, HttpExchange exchange)
|
||||
{
|
||||
process((HttpConnectionOverHTTP)connection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Throwable x)
|
||||
{
|
||||
getHttpClient().getExecutor().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
abort(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void send()
|
||||
{
|
||||
HttpConnectionOverHTTP connection = acquire();
|
||||
if (connection != null)
|
||||
process(connection, false);
|
||||
}
|
||||
|
||||
protected HttpConnectionOverHTTP acquire()
|
||||
{
|
||||
return (HttpConnectionOverHTTP)connectionPool.acquire();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Processes a new connection making it idle or active depending on whether requests are waiting to be sent.</p>
|
||||
* <p>A new connection is created when a request needs to be executed; it is possible that the request that
|
||||
* triggered the request creation is executed by another connection that was just released, so the new connection
|
||||
* may become idle.</p>
|
||||
* <p>If a request is waiting to be executed, it will be dequeued and executed by the new connection.</p>
|
||||
*
|
||||
* @param connection the new connection
|
||||
* @param dispatch whether to dispatch the processing to another thread
|
||||
*/
|
||||
protected void process(final HttpConnectionOverHTTP connection, boolean dispatch)
|
||||
{
|
||||
HttpClient client = getHttpClient();
|
||||
final HttpExchange exchange = getHttpExchanges().poll();
|
||||
LOG.debug("Processing exchange {} on connection {}", exchange, connection);
|
||||
if (exchange == null)
|
||||
{
|
||||
// TODO: review this part... may not be 100% correct
|
||||
// TODO: e.g. is client is not running, there should be no need to close the connection
|
||||
|
||||
if (!connectionPool.release(connection))
|
||||
connection.close();
|
||||
|
||||
if (!client.isRunning())
|
||||
{
|
||||
LOG.debug("{} is stopping", client);
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final Request request = exchange.getRequest();
|
||||
Throwable cause = request.getAbortCause();
|
||||
if (cause != null)
|
||||
{
|
||||
abort(exchange, cause);
|
||||
LOG.debug("Aborted before processing {}: {}", exchange, cause);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dispatch)
|
||||
{
|
||||
client.getExecutor().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
connection.send(exchange);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.send(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void release(HttpConnectionOverHTTP connection)
|
||||
{
|
||||
LOG.debug("{} released", connection);
|
||||
HttpClient client = getHttpClient();
|
||||
if (client.isRunning())
|
||||
{
|
||||
if (connectionPool.isActive(connection))
|
||||
process(connection, false);
|
||||
else
|
||||
LOG.debug("{} explicit", connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("{} is stopped", client);
|
||||
close(connection);
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Connection oldConnection)
|
||||
{
|
||||
super.close(oldConnection);
|
||||
connectionPool.remove(oldConnection);
|
||||
|
||||
// We need to execute queued requests even if this connection failed.
|
||||
// We may create a connection that is not needed, but it will eventually
|
||||
// idle timeout, so no worries
|
||||
if (!getHttpExchanges().isEmpty())
|
||||
{
|
||||
HttpConnectionOverHTTP newConnection = acquire();
|
||||
if (newConnection != null)
|
||||
process(newConnection, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
connectionPool.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
ContainerLifeCycle.dump(out, indent, Arrays.asList(connectionPool));
|
||||
connection.send(exchange);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.client.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
@ -35,14 +36,18 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* Invocations to the {@link #iterator()} method after the first will return an "empty" iterator
|
||||
* because the stream has been consumed on the first invocation.
|
||||
* <p />
|
||||
* It is possible to specify, at the constructor, a buffer size used to read content from the
|
||||
* stream, by default 4096 bytes.
|
||||
* <p />
|
||||
* However, it is possible for subclasses to override {@link #onRead(byte[], int, int)} to copy
|
||||
* the content read from the stream to another location (for example a file), and be able to
|
||||
* support multiple invocations of {@link #iterator()}, returning the iterator provided by this
|
||||
* class on the first invocation, and an iterator on the bytes copied to the other location
|
||||
* for subsequent invocations.
|
||||
* <p />
|
||||
* It is possible to specify, at the constructor, a buffer size used to read content from the
|
||||
* stream, by default 4096 bytes.
|
||||
* <p />
|
||||
* The {@link InputStream} passed to the constructor is by default closed when is it fully
|
||||
* consumed (or when an exception is thrown while reading it), unless otherwise specified
|
||||
* to the {@link #InputStreamContentProvider(java.io.InputStream, int, boolean) constructor}.
|
||||
*/
|
||||
public class InputStreamContentProvider implements ContentProvider
|
||||
{
|
||||
|
@ -50,6 +55,7 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
|
||||
private final InputStream stream;
|
||||
private final int bufferSize;
|
||||
private final boolean autoClose;
|
||||
|
||||
public InputStreamContentProvider(InputStream stream)
|
||||
{
|
||||
|
@ -57,9 +63,15 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
}
|
||||
|
||||
public InputStreamContentProvider(InputStream stream, int bufferSize)
|
||||
{
|
||||
this(stream, bufferSize, true);
|
||||
}
|
||||
|
||||
public InputStreamContentProvider(InputStream stream, int bufferSize, boolean autoClose)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.bufferSize = bufferSize;
|
||||
this.autoClose = autoClose;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,6 +148,7 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
else if (read < 0)
|
||||
{
|
||||
hasNext = Boolean.FALSE;
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -154,6 +167,7 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
// Signal we have more content to cause a call to
|
||||
// next() which will throw NoSuchElementException.
|
||||
hasNext = Boolean.TRUE;
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
|
@ -178,5 +192,20 @@ public class InputStreamContentProvider implements ContentProvider
|
|||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void close()
|
||||
{
|
||||
if (autoClose)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -863,4 +863,148 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestListenerForMultipleEventsIsInvokedOncePerEvent() throws Exception
|
||||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
Request.Listener listener = new Request.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onQueued(Request request)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBegin(Request request)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(Request request)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommit(Request request)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContent(Request request, ByteBuffer content)
|
||||
{
|
||||
// Should not be invoked
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Request request, Throwable failure)
|
||||
{
|
||||
// Should not be invoked
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Request request)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
};
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.onRequestQueued(listener)
|
||||
.onRequestBegin(listener)
|
||||
.onRequestHeaders(listener)
|
||||
.onRequestCommit(listener)
|
||||
.onRequestContent(listener)
|
||||
.onRequestSuccess(listener)
|
||||
.onRequestFailure(listener)
|
||||
.listener(listener)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
int expectedEventsTriggeredByOnRequestXXXListeners = 5;
|
||||
int expectedEventsTriggeredByListener = 5;
|
||||
int expected = expectedEventsTriggeredByOnRequestXXXListeners + expectedEventsTriggeredByListener;
|
||||
Assert.assertEquals(expected, counter.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseListenerForMultipleEventsIsInvokedOncePerEvent() throws Exception
|
||||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Response.Listener listener = new Response.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onBegin(Response response)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHeader(Response response, HttpField field)
|
||||
{
|
||||
// Number of header may vary, so don't count
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
// Should not be invoked
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Response response)
|
||||
{
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Response response, Throwable failure)
|
||||
{
|
||||
// Should not be invoked
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertEquals(200, result.getResponse().getStatus());
|
||||
counter.incrementAndGet();
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.onResponseBegin(listener)
|
||||
.onResponseHeader(listener)
|
||||
.onResponseHeaders(listener)
|
||||
.onResponseContent(listener)
|
||||
.onResponseSuccess(listener)
|
||||
.onResponseFailure(listener)
|
||||
.send(listener);
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
int expectedEventsTriggeredByOnResponseXXXListeners = 3;
|
||||
int expectedEventsTriggeredByCompletionListener = 4;
|
||||
int expected = expectedEventsTriggeredByOnResponseXXXListeners + expectedEventsTriggeredByCompletionListener;
|
||||
Assert.assertEquals(expected, counter.get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))
|
||||
{
|
||||
@Override
|
||||
protected void process(HttpConnectionOverHTTP connection, boolean dispatch)
|
||||
public void process(HttpConnectionOverHTTP connection, boolean dispatch)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
* and when the {@link EndPoint} signals read readyness, this {@link Connection} can
|
||||
* read bytes from the network and interpret them.</p>
|
||||
*/
|
||||
public interface Connection extends AutoCloseable
|
||||
public interface Connection extends Closeable
|
||||
{
|
||||
public void addListener(Listener listener);
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@ import java.net.Socket;
|
|||
import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
|
@ -58,14 +56,10 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
*/
|
||||
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(SelectorManager.class);
|
||||
public static final String SUBMIT_KEY_UPDATES="org.eclipse.jetty.io.SelectorManager.submitKeyUpdates";
|
||||
/**
|
||||
* The default connect timeout, in milliseconds
|
||||
*/
|
||||
public static final String SUBMIT_KEY_UPDATES = "org.eclipse.jetty.io.SelectorManager.submitKeyUpdates";
|
||||
public static final int DEFAULT_CONNECT_TIMEOUT = 15000;
|
||||
|
||||
private final static boolean __submitKeyUpdates=Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES,"FALSE"));
|
||||
protected static final Logger LOG = Log.getLogger(SelectorManager.class);
|
||||
private final static boolean __submitKeyUpdates = Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES, "false"));
|
||||
|
||||
private final Executor executor;
|
||||
private final Scheduler scheduler;
|
||||
|
@ -233,7 +227,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
connection.onOpen();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (isRunning())
|
||||
LOG.warn("Exception while notifying connection " + connection, x);
|
||||
|
@ -253,9 +247,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
connection.onClose();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Exception while notifying connection " + connection, x);
|
||||
LOG.debug("Exception while notifying connection " + connection, x);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,11 +362,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
public void updateKey(Runnable update)
|
||||
{
|
||||
if (__submitKeyUpdates)
|
||||
{
|
||||
submit(update);
|
||||
}
|
||||
else
|
||||
{
|
||||
update.run();
|
||||
|
||||
runChange(update);
|
||||
if (_state.compareAndSet(State.SELECT, State.WAKEUP))
|
||||
wakeup();
|
||||
}
|
||||
|
@ -435,8 +430,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
protected void runChange(Runnable change)
|
||||
{
|
||||
LOG.debug("Running change {}", change);
|
||||
change.run();
|
||||
try
|
||||
{
|
||||
LOG.debug("Running change {}", change);
|
||||
change.run();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.debug("Could not run change " + change, x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -520,7 +522,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
selectedKeys.clear();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (isRunning())
|
||||
LOG.warn(x);
|
||||
|
@ -553,7 +555,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
if (attachment instanceof EndPoint)
|
||||
((EndPoint)attachment).close();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.warn("Could not process key for channel " + key.channel(), x);
|
||||
if (attachment instanceof EndPoint)
|
||||
|
@ -563,10 +565,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
private void processConnect(SelectionKey key, Connect connect)
|
||||
{
|
||||
key.attach(connect.attachment);
|
||||
SocketChannel channel = (SocketChannel)key.channel();
|
||||
try
|
||||
{
|
||||
key.attach(connect.attachment);
|
||||
boolean connected = finishConnect(channel);
|
||||
if (connected)
|
||||
{
|
||||
|
@ -580,10 +582,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
throw new ConnectException();
|
||||
}
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
connect.failed(x);
|
||||
closeNoExceptions(channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,7 +594,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
|
@ -740,8 +741,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
EndPoint endpoint = createEndPoint(_channel, key);
|
||||
key.attach(endpoint);
|
||||
}
|
||||
catch (IOException x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
closeNoExceptions(_channel);
|
||||
LOG.debug(x);
|
||||
}
|
||||
}
|
||||
|
@ -768,7 +770,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
channel.register(_selector, SelectionKey.OP_CONNECT, this);
|
||||
}
|
||||
catch (ClosedSelectorException | ClosedChannelException x)
|
||||
catch (Throwable x)
|
||||
{
|
||||
failed(x);
|
||||
}
|
||||
|
@ -779,22 +781,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
if (failed.compareAndSet(false, true))
|
||||
{
|
||||
timeout.cancel();
|
||||
close();
|
||||
closeNoExceptions(channel);
|
||||
connectionFailed(channel, failure, attachment);
|
||||
}
|
||||
}
|
||||
|
||||
private void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
channel.close();
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectTimeout implements Runnable
|
||||
|
@ -878,7 +868,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
try
|
||||
{
|
||||
endPoint.getConnection().close();
|
||||
closeNoExceptions(endPoint.getConnection());
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ import javax.security.auth.callback.CallbackHandler;
|
|||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
|
||||
|
@ -199,9 +200,14 @@ public abstract class AbstractLoginModule implements LoginModule
|
|||
callbacks[2] = new PasswordCallback("Enter password", false); //only used if framework does not support the ObjectCallback
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean isIgnored ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public abstract UserInfo getUserInfo (String username) throws Exception;
|
||||
|
||||
|
||||
|
@ -214,7 +220,10 @@ public abstract class AbstractLoginModule implements LoginModule
|
|||
public boolean login() throws LoginException
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
if (isIgnored())
|
||||
return false;
|
||||
|
||||
if (callbackHandler == null)
|
||||
throw new LoginException ("No callback handler");
|
||||
|
||||
|
@ -231,7 +240,7 @@ public abstract class AbstractLoginModule implements LoginModule
|
|||
if ((webUserName == null) || (webCredential == null))
|
||||
{
|
||||
setAuthenticated(false);
|
||||
return isAuthenticated();
|
||||
throw new FailedLoginException();
|
||||
}
|
||||
|
||||
UserInfo userInfo = getUserInfo(webUserName);
|
||||
|
@ -239,12 +248,16 @@ public abstract class AbstractLoginModule implements LoginModule
|
|||
if (userInfo == null)
|
||||
{
|
||||
setAuthenticated(false);
|
||||
return isAuthenticated();
|
||||
throw new FailedLoginException();
|
||||
}
|
||||
|
||||
currentUser = new JAASUserInfo(userInfo);
|
||||
setAuthenticated(currentUser.checkCredential(webCredential));
|
||||
return isAuthenticated();
|
||||
|
||||
if (isAuthenticated())
|
||||
return true;
|
||||
else
|
||||
throw new FailedLoginException();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -256,7 +269,8 @@ public abstract class AbstractLoginModule implements LoginModule
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
if (e instanceof LoginException)
|
||||
throw (LoginException)e;
|
||||
throw new LoginException (e.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,9 +112,10 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
|||
PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename);
|
||||
if (propertyUserStore == null)
|
||||
throw new IllegalStateException("PropertyUserStore should never be null here!");
|
||||
|
||||
|
||||
LOG.debug("Checking PropertyUserStore "+_filename+" for "+userName);
|
||||
UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
|
||||
if(userIdentity==null)
|
||||
if (userIdentity==null)
|
||||
return null;
|
||||
|
||||
Set<Principal> principals = userIdentity.getSubject().getPrincipals();
|
||||
|
@ -127,7 +128,7 @@ public class PropertyFileLoginModule extends AbstractLoginModule
|
|||
}
|
||||
|
||||
Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next();
|
||||
LOG.debug("Found: " + userName + " in PropertyUserStore");
|
||||
LOG.debug("Found: " + userName + " in PropertyUserStore "+_filename);
|
||||
return new UserInfo(userName, credential, roles);
|
||||
}
|
||||
|
||||
|
|
|
@ -288,6 +288,9 @@ public class JspcMojo extends AbstractMojo
|
|||
|
||||
Thread.currentThread().setContextClassLoader(webAppClassLoader);
|
||||
|
||||
if (jspc == null)
|
||||
jspc = new JspC();
|
||||
|
||||
jspc.setWebXmlFragment(webXmlFragment);
|
||||
jspc.setUriroot(webAppSourceDirectory);
|
||||
jspc.setOutputDir(generatedClasses);
|
||||
|
|
|
@ -132,11 +132,20 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
* The temporary directory to use for the webapp.
|
||||
* Defaults to target/tmp
|
||||
*
|
||||
* @parameter expression="${project.build.directory}/tmp"
|
||||
* @parameter alias="tmpDirectory" expression="${project.build.directory}/tmp"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected File tmpDirectory;
|
||||
protected File tempDirectory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Whether temporary directory contents should survive webapp restarts.
|
||||
*
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
private boolean persistTempDirectory;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -418,12 +427,14 @@ public class JettyRunForkedMojo extends AbstractMojo
|
|||
props.put("context.path", contextPath);
|
||||
|
||||
//sort out the tmp directory (make it if it doesn't exist)
|
||||
if (tmpDirectory != null)
|
||||
if (tempDirectory != null)
|
||||
{
|
||||
if (!tmpDirectory.exists())
|
||||
tmpDirectory.mkdirs();
|
||||
props.put("tmp.dir", tmpDirectory.getAbsolutePath());
|
||||
if (!tempDirectory.exists())
|
||||
tempDirectory.mkdirs();
|
||||
props.put("tmp.dir", tempDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
props.put("tmp.dir.persist", Boolean.toString(persistTempDirectory));
|
||||
|
||||
//sort out base dir of webapp
|
||||
if (webAppSourceDirectory == null || !webAppSourceDirectory.exists())
|
||||
|
|
|
@ -284,9 +284,6 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
|
|||
{
|
||||
LOG.debug("Unpacking overlay: " + overlay);
|
||||
|
||||
//resolve if not already resolved
|
||||
resolveTempDirectory(context);
|
||||
|
||||
if (overlay.getResource() == null)
|
||||
return null; //nothing to unpack
|
||||
|
||||
|
|
|
@ -207,6 +207,9 @@ public class Starter
|
|||
if (str != null)
|
||||
webApp.setTempDirectory(new File(str.trim()));
|
||||
|
||||
str = (String)props.getProperty("tmp.dir.persist");
|
||||
if (str != null)
|
||||
webApp.setPersistTempDirectory(Boolean.valueOf(str));
|
||||
|
||||
// - the base directory
|
||||
str = (String)props.getProperty("base.dir");
|
||||
|
@ -219,7 +222,7 @@ public class Starter
|
|||
// - put virtual webapp base resource first on resource path or not
|
||||
str = (String)props.getProperty("base.first");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
webApp.setBaseAppFirst(Boolean.getBoolean(str));
|
||||
webApp.setBaseAppFirst(Boolean.valueOf(str));
|
||||
|
||||
|
||||
//For overlays
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<name>Fragment1</name>
|
||||
|
||||
<ordering>
|
||||
<after>others</after>
|
||||
<after><others/></after>
|
||||
</ordering>
|
||||
|
||||
<resource-ref>
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
<name>Fragment2</name>
|
||||
|
||||
<ordering>
|
||||
<after>others</after>
|
||||
<after><others/></after>
|
||||
</ordering>
|
||||
|
||||
<resource-ref>
|
||||
<res-ref-name>jdbc/mydatasource</res-ref-name>
|
||||
<res-type>javax.sql.DataSource</res-type>
|
||||
<res-auth>User</res-auth>
|
||||
<res-auth>Application</res-auth>
|
||||
<!--
|
||||
<injection-target>
|
||||
<injection-target-class>com.acme.Bar</injection-target-class>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<name>Fragment3</name>
|
||||
|
||||
<ordering>
|
||||
<after>others</after>
|
||||
<after><others/></after>
|
||||
</ordering>
|
||||
|
||||
<resource-ref>
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
<Arg name="threadpool">
|
||||
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
|
||||
<Set name="minThreads">16</Set>
|
||||
<Set name="maxThreads">256</Set>
|
||||
<Set name="minThreads"><Property name="java.proxy.threadpool.min" default="16"/></Set>
|
||||
<Set name="maxThreads"><Property name="java.proxy.threadpool.max" default="256"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
|||
<Arg name="server"><Ref refid="Proxy" /></Arg>
|
||||
<Set name="host"><Property name="jetty.host" /></Set>
|
||||
<Set name="port"><Property name="jetty.port" default="8888"/></Set>
|
||||
<Set name="idleTimeout">300000</Set>
|
||||
<Set name="idleTimeout"><Property name="java.proxy.idleTimeout" default="300000"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<Arg>/</Arg>
|
||||
<Call name="setInitParameter">
|
||||
<Arg>maxThreads</Arg>
|
||||
<Arg>128</Arg>
|
||||
<Arg><Property name="java.proxy.threads.max" default="128"/></Arg>
|
||||
</Call>
|
||||
</Call>
|
||||
</New>
|
||||
|
@ -42,7 +42,7 @@
|
|||
</New>
|
||||
</Set>
|
||||
|
||||
<Set name="stopAtShutdown">true</Set>
|
||||
<Set name="stopTimeout">1000</Set>
|
||||
<Set name="stopAtShutdown"><Property name="java.proxy.stopAtShutdown" default="true"/></Set>
|
||||
<Set name="stopTimeout"><Property name="java.proxy.stopTimeout" default="1000"/></Set>
|
||||
|
||||
</Configure>
|
||||
|
|
|
@ -11,3 +11,12 @@ lib/jetty-proxy-${jetty.version}.jar
|
|||
|
||||
[xml]
|
||||
etc/jetty-proxy.xml
|
||||
|
||||
[ini-template]
|
||||
## Proxy Configuration
|
||||
jetty.proxy.threadpool.min=16
|
||||
jetty.proxy.threadpool.max=256
|
||||
jetty.proxy.idleTimeout=300000
|
||||
jetty.proxy.threads.max=128
|
||||
jetty.proxy.stopAtShutdown=true
|
||||
jetty.proxy.stopTimeout=1000
|
||||
|
|
|
@ -137,6 +137,11 @@ public class ProxyServlet extends HttpServlet
|
|||
}
|
||||
}
|
||||
|
||||
public String getViaHost()
|
||||
{
|
||||
return _viaHost;
|
||||
}
|
||||
|
||||
public long getTimeout()
|
||||
{
|
||||
return _timeout;
|
||||
|
@ -419,11 +424,8 @@ public class ProxyServlet extends HttpServlet
|
|||
proxyRequest.header(HttpHeader.HOST, _hostHeader);
|
||||
|
||||
// Add proxy headers
|
||||
proxyRequest.header(HttpHeader.VIA, "http/1.1 " + _viaHost);
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_FOR, request.getRemoteAddr());
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_PROTO, request.getScheme());
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_HOST, request.getHeader(HttpHeader.HOST.asString()));
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_SERVER, request.getLocalName());
|
||||
addViaHeader(proxyRequest);
|
||||
addXForwardedHeaders(proxyRequest, request);
|
||||
|
||||
if (hasContent)
|
||||
{
|
||||
|
@ -488,6 +490,19 @@ public class ProxyServlet extends HttpServlet
|
|||
proxyRequest.send(new ProxyResponseListener(request, response));
|
||||
}
|
||||
|
||||
protected Request addViaHeader(Request proxyRequest)
|
||||
{
|
||||
return proxyRequest.header(HttpHeader.VIA, "http/1.1 " + getViaHost());
|
||||
}
|
||||
|
||||
protected void addXForwardedHeaders(Request proxyRequest, HttpServletRequest request)
|
||||
{
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_FOR, request.getRemoteAddr());
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_PROTO, request.getScheme());
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_HOST, request.getHeader(HttpHeader.HOST.asString()));
|
||||
proxyRequest.header(HttpHeader.X_FORWARDED_SERVER, request.getLocalName());
|
||||
}
|
||||
|
||||
protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
|
||||
{
|
||||
for (HttpField field : proxyResponse.getHeaders())
|
||||
|
|
|
@ -44,9 +44,9 @@ service jetty
|
|||
-->
|
||||
|
||||
<!-- sane defaults -->
|
||||
<Set name="idleTimeout">300000</Set>
|
||||
<Set name="Acceptors">2</Set>
|
||||
<Set name="statsOn">false</Set>
|
||||
<Set name="idleTimeout"><Property name="jetty.xinetd.idleTimeout" default="300000"/></Set>
|
||||
<Set name="Acceptors"><Property name="jetty.xinetd.acceptors" default="2"/></Set>
|
||||
<Set name="statsOn"><Property name="jetty.xinetd.statsOn" default="false"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -1,2 +1,11 @@
|
|||
#
|
||||
# Module to add all lib/ext/*.jar files to classpath
|
||||
#
|
||||
|
||||
[lib]
|
||||
lib/ext/*.jar
|
||||
|
||||
[files]
|
||||
lib/
|
||||
lib/ext/
|
||||
|
||||
|
|
|
@ -3,4 +3,8 @@
|
|||
#
|
||||
|
||||
[lib]
|
||||
resources
|
||||
resources
|
||||
|
||||
[files]
|
||||
resources/
|
||||
|
||||
|
|
|
@ -7,3 +7,11 @@ server
|
|||
|
||||
[xml]
|
||||
etc/jetty-xinetd.xml
|
||||
|
||||
[ini-template]
|
||||
## Xinetd Configuration
|
||||
## See ${jetty.home}/etc/jetty-xinetd.xml for example service entry
|
||||
jetty.xinetd.idleTimeout=300000
|
||||
jetty.xinetd.acceptors=2
|
||||
jetty.xinetd.statsOn=false
|
||||
|
||||
|
|
|
@ -420,6 +420,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
boolean committed = sendResponse(info, null, true);
|
||||
if (!committed)
|
||||
LOG.warn("Could not send response error 500: "+x);
|
||||
_request.getAsyncContext().complete();
|
||||
}
|
||||
else if (isCommitted())
|
||||
{
|
||||
|
|
|
@ -485,7 +485,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
{
|
||||
case NEED_HEADER:
|
||||
{
|
||||
if (_lastContent && _content!=null && BufferUtil.space(_content)>_config.getResponseHeaderSize() && _content.hasArray() )
|
||||
// Look for optimisation to avoid allocating a _header buffer
|
||||
if (_lastContent && _content!=null && !_content.isReadOnly() && _content.hasArray() && BufferUtil.space(_content)>_config.getResponseHeaderSize() )
|
||||
{
|
||||
// use spare space in content buffer for header buffer
|
||||
int p=_content.position();
|
||||
|
|
|
@ -302,7 +302,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
// write any remaining content in the buffer directly
|
||||
if (len>0)
|
||||
_channel.write(ByteBuffer.wrap(b, off, len), complete);
|
||||
// pass as readonly to avoid space stealing optimisation in HttpConnection
|
||||
_channel.write(ByteBuffer.wrap(b, off, len).asReadOnlyBuffer(), complete);
|
||||
else if (complete)
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER,complete);
|
||||
|
||||
|
@ -440,12 +441,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Blocking send of content.
|
||||
* @param content The content to send
|
||||
* @param content The content to send.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendContent(ByteBuffer content) throws IOException
|
||||
{
|
||||
final BlockingCallback callback =_channel.getWriteBlockingCallback();
|
||||
if (content.hasArray()&&content.limit()<content.capacity())
|
||||
content=content.asReadOnlyBuffer();
|
||||
_channel.write(content,true,callback);
|
||||
callback.block();
|
||||
}
|
||||
|
@ -487,7 +490,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
callback.block();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Asynchronous send of content.
|
||||
* @param content The content to send
|
||||
|
@ -495,6 +497,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
*/
|
||||
public void sendContent(ByteBuffer content, final Callback callback)
|
||||
{
|
||||
if (content.hasArray()&&content.limit()<content.capacity())
|
||||
content=content.asReadOnlyBuffer();
|
||||
_channel.write(content,true,new Callback()
|
||||
{
|
||||
@Override
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p>A {@link Connector} for TCP/IP network connectors</p>
|
||||
*/
|
||||
public interface NetworkConnector extends Connector, AutoCloseable
|
||||
public interface NetworkConnector extends Connector, Closeable
|
||||
{
|
||||
/**
|
||||
* <p>Performs the activities needed to open the network communication
|
||||
|
|
|
@ -355,9 +355,10 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
futures.add(connector.shutdown());
|
||||
|
||||
// Then tell the contexts that we are shutting down
|
||||
Handler[] contexts = getChildHandlersByClass(Graceful.class);
|
||||
for (Handler context : contexts)
|
||||
futures.add(((Graceful)context).shutdown());
|
||||
|
||||
Handler[] gracefuls = getChildHandlersByClass(Graceful.class);
|
||||
for (Handler graceful : gracefuls)
|
||||
futures.add(((Graceful)graceful).shutdown());
|
||||
|
||||
// Shall we gracefully wait for zero connections?
|
||||
long stopTimeout = getStopTimeout();
|
||||
|
|
|
@ -19,8 +19,11 @@
|
|||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -32,14 +35,16 @@ import org.eclipse.jetty.server.AsyncContextEvent;
|
|||
import org.eclipse.jetty.server.HttpChannelState;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.statistic.CounterStatistic;
|
||||
import org.eclipse.jetty.util.statistic.SampleStatistic;
|
||||
|
||||
@ManagedObject("Request Statistics Gathering")
|
||||
public class StatisticsHandler extends HandlerWrapper
|
||||
public class StatisticsHandler extends HandlerWrapper implements Graceful
|
||||
{
|
||||
private final AtomicLong _statsStartedAt = new AtomicLong();
|
||||
|
||||
|
@ -59,6 +64,8 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
private final AtomicInteger _responses5xx = new AtomicInteger();
|
||||
private final AtomicLong _responsesTotalBytes = new AtomicLong();
|
||||
|
||||
private final AtomicReference<FutureCallback> _shutdown=new AtomicReference<>();
|
||||
|
||||
private final AsyncListener _onCompletion = new AsyncListener()
|
||||
{
|
||||
@Override
|
||||
|
@ -86,14 +93,21 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
Request request = state.getBaseRequest();
|
||||
final long elapsed = System.currentTimeMillis()-request.getTimeStamp();
|
||||
|
||||
_requestStats.decrement();
|
||||
long d=_requestStats.decrement();
|
||||
_requestTimeStats.set(elapsed);
|
||||
|
||||
updateResponse(request);
|
||||
|
||||
_asyncWaitStats.decrement();
|
||||
|
||||
// If we have no more dispatches, should we signal shutdown?
|
||||
if (d==0)
|
||||
{
|
||||
FutureCallback shutdown = _shutdown.get();
|
||||
if (shutdown!=null)
|
||||
shutdown.succeeded();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -162,9 +176,18 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
}
|
||||
else if (state.isInitial())
|
||||
{
|
||||
_requestStats.decrement();
|
||||
long d=_requestStats.decrement();
|
||||
_requestTimeStats.set(dispatched);
|
||||
updateResponse(request);
|
||||
|
||||
// If we have no more dispatches, should we signal shutdown?
|
||||
FutureCallback shutdown = _shutdown.get();
|
||||
if (shutdown!=null)
|
||||
{
|
||||
httpResponse.flushBuffer();
|
||||
if (d==0)
|
||||
shutdown.succeeded();
|
||||
}
|
||||
}
|
||||
// else onCompletion will handle it.
|
||||
}
|
||||
|
@ -205,9 +228,20 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_shutdown.set(null);
|
||||
super.doStart();
|
||||
statsReset();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
FutureCallback shutdown = _shutdown.get();
|
||||
if (shutdown!=null && !shutdown.isDone())
|
||||
shutdown.failed(new TimeoutException());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of requests handled by this handler
|
||||
|
@ -523,4 +557,15 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
FutureCallback shutdown=new FutureCallback(false);
|
||||
_shutdown.compareAndSet(null,shutdown);
|
||||
shutdown=_shutdown.get();
|
||||
if (_dispatchedStats.getCurrent()==0)
|
||||
shutdown.succeeded();
|
||||
return shutdown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class GracefulStopTest
|
||||
{
|
||||
private Server server;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception
|
||||
{
|
||||
server = new Server(0);
|
||||
StatisticsHandler stats = new StatisticsHandler();
|
||||
TestHandler test=new TestHandler();
|
||||
server.setHandler(stats);
|
||||
stats.setHandler(test);
|
||||
server.setStopTimeout(10 * 1000);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraceful() throws Exception
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
server.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
||||
try(Socket socket = new Socket("localhost",server.getBean(NetworkConnector.class).getLocalPort());)
|
||||
{
|
||||
socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StringUtil.__ISO_8859_1_CHARSET));
|
||||
String out = IO.toString(socket.getInputStream());
|
||||
Assert.assertThat(out,Matchers.containsString("200 OK"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(final String s, final Request request, final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
}
|
||||
|
||||
httpServletResponse.getWriter().write("OK");
|
||||
httpServletResponse.setStatus(200);
|
||||
request.setHandled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
|
@ -26,6 +27,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -81,6 +83,26 @@ public class HttpOutputTest
|
|||
assertThat(response,containsString("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendArray() throws Exception
|
||||
{
|
||||
byte[] buffer=new byte[16*1024];
|
||||
Arrays.fill(buffer,0,4*1024,(byte)0x99);
|
||||
Arrays.fill(buffer,4*1024,12*1024,(byte)0x58);
|
||||
Arrays.fill(buffer,12*1024,16*1024,(byte)0x66);
|
||||
_handler._content=ByteBuffer.wrap(buffer);
|
||||
_handler._content.limit(12*1024);
|
||||
_handler._content.position(4*1024);
|
||||
String response=_connector.getResponses("GET / HTTP/1.0\nHost: localhost:80\n\n");
|
||||
assertThat(response,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("\r\nXXXXXXXXXXXXXXXXXXXXXXXXXXX"));
|
||||
|
||||
for (int i=0;i<4*1024;i++)
|
||||
assertEquals("i="+i,(byte)0x99,buffer[i]);
|
||||
for (int i=12*1024;i<16*1024;i++)
|
||||
assertEquals("i="+i,(byte)0x66,buffer[i]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendInputStreamSimple() throws Exception
|
||||
{
|
||||
|
@ -386,9 +408,9 @@ public class HttpOutputTest
|
|||
boolean _async;
|
||||
ByteBuffer _buffer;
|
||||
byte[] _bytes;
|
||||
ByteBuffer _content;
|
||||
InputStream _contentInputStream;
|
||||
ReadableByteChannel _contentChannel;
|
||||
ByteBuffer _content;
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
|
@ -398,6 +420,7 @@ public class HttpOutputTest
|
|||
|
||||
final HttpOutput out = (HttpOutput) response.getOutputStream();
|
||||
|
||||
|
||||
if (_contentInputStream!=null)
|
||||
{
|
||||
out.sendContent(_contentInputStream);
|
||||
|
@ -510,10 +533,13 @@ public class HttpOutputTest
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_content!=null)
|
||||
{
|
||||
out.sendContent(_content);
|
||||
response.setContentLength(_content.remaining());
|
||||
if (_content.hasArray())
|
||||
out.write(_content.array(),_content.arrayOffset()+_content.position(),_content.remaining());
|
||||
else
|
||||
out.sendContent(_content);
|
||||
_content=null;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -82,9 +82,7 @@ public class SlowClientWithPipelinedRequestTest
|
|||
}
|
||||
}
|
||||
|
||||
// TODO merged from jetty-8 - not working???
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSlowClientWithPipelinedRequest() throws Exception
|
||||
{
|
||||
final int contentLength = 512 * 1024;
|
||||
|
|
|
@ -569,10 +569,10 @@ public class ServletHandler extends ScopedHandler
|
|||
LOG.debug(request.toString());
|
||||
}
|
||||
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
|
||||
if (th instanceof UnavailableException)
|
||||
{
|
||||
UnavailableException ue = (UnavailableException)th;
|
||||
|
@ -586,6 +586,10 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
else
|
||||
LOG.debug("Response already committed",th);
|
||||
|
||||
// Complete async requests
|
||||
if (request.isAsyncStarted())
|
||||
request.getAsyncContext().complete();
|
||||
}
|
||||
catch(Error e)
|
||||
{
|
||||
|
@ -596,15 +600,16 @@ public class ServletHandler extends ScopedHandler
|
|||
LOG.warn("Error for "+request.getRequestURI(),e);
|
||||
if(LOG.isDebugEnabled())LOG.debug(request.toString());
|
||||
|
||||
// TODO httpResponse.getHttpConnection().forceClose();
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
|
||||
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
else
|
||||
LOG.debug("Response already committed for handling ",e);
|
||||
|
||||
// Complete async requests
|
||||
if (request.isAsyncStarted())
|
||||
request.getAsyncContext().complete();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@ import javax.servlet.http.HttpServletResponseWrapper;
|
|||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.QuietServletException;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
|
@ -68,7 +69,7 @@ public class AsyncContextTest
|
|||
_server = new Server();
|
||||
_contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
||||
_connector = new LocalConnector(_server);
|
||||
_connector.setIdleTimeout(30000);
|
||||
_connector.setIdleTimeout(5000);
|
||||
_server.setConnectors(new Connector[]
|
||||
{ _connector });
|
||||
|
||||
|
@ -76,6 +77,7 @@ public class AsyncContextTest
|
|||
_contextHandler.addServlet(new ServletHolder(new TestServlet()),"/servletPath");
|
||||
_contextHandler.addServlet(new ServletHolder(new TestServlet()),"/path with spaces/servletPath");
|
||||
_contextHandler.addServlet(new ServletHolder(new TestServlet2()),"/servletPath2");
|
||||
_contextHandler.addServlet(new ServletHolder(new TestStartThrowServlet()),"/startthrow/*");
|
||||
_contextHandler.addServlet(new ServletHolder(new ForwardingServlet()),"/forward");
|
||||
_contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()),"/dispatchingServlet");
|
||||
_contextHandler.addServlet(new ServletHolder(new ExpireServlet()),"/expire/*");
|
||||
|
@ -84,7 +86,8 @@ public class AsyncContextTest
|
|||
|
||||
ErrorPageErrorHandler error_handler = new ErrorPageErrorHandler();
|
||||
_contextHandler.setErrorHandler(error_handler);
|
||||
error_handler.addErrorPage(500,"/error");
|
||||
error_handler.addErrorPage(500,"/error/500");
|
||||
error_handler.addErrorPage(IOException.class.getName(),"/error/IOE");
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.setHandlers(new Handler[]
|
||||
|
@ -116,6 +119,25 @@ public class AsyncContextTest
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartThrow() throws Exception
|
||||
{
|
||||
String request = "GET /ctx/startthrow HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
+ "Connection: close\r\n" + "\r\n";
|
||||
String responseString = _connector.getResponses(request);
|
||||
|
||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
||||
|
||||
assertEquals("HTTP/1.1 500 Server Error",br.readLine());
|
||||
br.readLine();// connection close
|
||||
br.readLine();// server
|
||||
br.readLine();// empty
|
||||
|
||||
Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
|
||||
Assert.assertEquals("error servlet","PathInfo= /IOE",br.readLine());
|
||||
Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: Test",br.readLine());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchAsyncContext() throws Exception
|
||||
{
|
||||
|
@ -327,6 +349,7 @@ public class AsyncContextTest
|
|||
br.readLine();// empty
|
||||
|
||||
Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
|
||||
Assert.assertEquals("error servlet","PathInfo= /500",br.readLine());
|
||||
Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: TEST",br.readLine());
|
||||
}
|
||||
|
||||
|
@ -365,6 +388,7 @@ public class AsyncContextTest
|
|||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
response.getOutputStream().print("ERROR: " + request.getServletPath() + "\n");
|
||||
response.getOutputStream().print("PathInfo= " + request.getPathInfo() + "\n");
|
||||
if (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)!=null)
|
||||
response.getOutputStream().print("EXCEPTION: " + request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) + "\n");
|
||||
}
|
||||
|
@ -462,6 +486,21 @@ public class AsyncContextTest
|
|||
asyncContext.start(new AsyncRunnable(asyncContext));
|
||||
}
|
||||
}
|
||||
|
||||
private class TestStartThrowServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
if (request.getDispatcherType()==DispatcherType.REQUEST)
|
||||
{
|
||||
request.startAsync(request, response);
|
||||
throw new QuietServletException(new IOException("Test"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AsyncRunnable implements Runnable
|
||||
{
|
||||
|
|
|
@ -6,6 +6,16 @@
|
|||
etc/jetty-logging.xml
|
||||
|
||||
[ini-template]
|
||||
## STDERR / STDOUT Logging
|
||||
## Logging Configuration
|
||||
# Configure jetty logging for default internal behavior STDERR output
|
||||
# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
|
||||
# Configure jetty logging for slf4j
|
||||
# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
|
||||
|
||||
# Configure jetty logging for java.util.logging
|
||||
# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog
|
||||
|
||||
# STDERR / STDOUT Logging
|
||||
# Number of days to retain logs
|
||||
# jetty.log.retain=90
|
||||
|
|
|
@ -35,12 +35,12 @@ public class MultiPartOutputStream extends FilterOutputStream
|
|||
private static final byte[] __CRLF={'\r','\n'};
|
||||
private static final byte[] __DASHDASH={'-','-'};
|
||||
|
||||
public static String MULTIPART_MIXED="multipart/mixed";
|
||||
public static String MULTIPART_X_MIXED_REPLACE="multipart/x-mixed-replace";
|
||||
public static final String MULTIPART_MIXED="multipart/mixed";
|
||||
public static final String MULTIPART_X_MIXED_REPLACE="multipart/x-mixed-replace";
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String boundary;
|
||||
private byte[] boundaryBytes;
|
||||
private final String boundary;
|
||||
private final byte[] boundaryBytes;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private boolean inPart=false;
|
||||
|
@ -54,8 +54,15 @@ public class MultiPartOutputStream extends FilterOutputStream
|
|||
boundary = "jetty"+System.identityHashCode(this)+
|
||||
Long.toString(System.currentTimeMillis(),36);
|
||||
boundaryBytes=boundary.getBytes(StringUtil.__ISO_8859_1);
|
||||
}
|
||||
|
||||
inPart=false;
|
||||
public MultiPartOutputStream(OutputStream out, String boundary)
|
||||
throws IOException
|
||||
{
|
||||
super(out);
|
||||
|
||||
this.boundary = boundary;
|
||||
boundaryBytes=boundary.getBytes(StringUtil.__ISO_8859_1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -66,14 +73,20 @@ public class MultiPartOutputStream extends FilterOutputStream
|
|||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
if (inPart)
|
||||
try
|
||||
{
|
||||
if (inPart)
|
||||
out.write(__CRLF);
|
||||
out.write(__DASHDASH);
|
||||
out.write(boundaryBytes);
|
||||
out.write(__DASHDASH);
|
||||
out.write(__CRLF);
|
||||
out.write(__DASHDASH);
|
||||
out.write(boundaryBytes);
|
||||
out.write(__DASHDASH);
|
||||
out.write(__CRLF);
|
||||
inPart=false;
|
||||
super.close();
|
||||
inPart=false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -55,37 +55,31 @@ public class CounterStatistic
|
|||
/**
|
||||
* @param delta the amount to add to the count
|
||||
*/
|
||||
public void add(final long delta)
|
||||
public long add(final long delta)
|
||||
{
|
||||
long value=_curr.addAndGet(delta);
|
||||
if (delta > 0)
|
||||
{
|
||||
_total.addAndGet(delta);
|
||||
Atomics.updateMax(_max,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param delta the amount to subtract the count by.
|
||||
*/
|
||||
public void subtract(final long delta)
|
||||
{
|
||||
add(-delta);
|
||||
Atomics.updateMax(_max,value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public void increment()
|
||||
public long increment()
|
||||
{
|
||||
add(1);
|
||||
return add(1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public void decrement()
|
||||
public long decrement()
|
||||
{
|
||||
add(-1);
|
||||
return add(-1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -154,6 +154,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
private String[] _contextWhiteList = null;
|
||||
|
||||
private File _tmpDir;
|
||||
private boolean _persistTmpDir = false;
|
||||
|
||||
private String _war;
|
||||
private String _extraClasspath;
|
||||
private Throwable _unavailableException;
|
||||
|
@ -1222,7 +1224,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
LOG.warn(e);
|
||||
}
|
||||
_tmpDir=dir;
|
||||
setAttribute(TEMPDIR,_tmpDir);
|
||||
setAttribute(TEMPDIR,_tmpDir);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1232,6 +1234,27 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
return _tmpDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true the temp directory for this
|
||||
* webapp will be kept when the webapp stops. Otherwise,
|
||||
* it will be deleted.
|
||||
*
|
||||
* @param delete
|
||||
*/
|
||||
public void setPersistTempDirectory(boolean persist)
|
||||
{
|
||||
_persistTmpDir = persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isPersistTempDirectory()
|
||||
{
|
||||
return _persistTmpDir;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param war The war to set as a file name or URL
|
||||
|
@ -1480,5 +1503,4 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
{
|
||||
return _metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.net.URLClassLoader;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -57,17 +58,15 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
* resource base as a resource collection.
|
||||
*/
|
||||
public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources";
|
||||
|
||||
|
||||
protected Resource _preUnpackBaseResource;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void preConfigure(final WebAppContext context) throws Exception
|
||||
{
|
||||
// Look for a work directory
|
||||
File work = findWorkDirectory(context);
|
||||
if (work != null)
|
||||
makeTempDirectory(work, context, false);
|
||||
|
||||
//Make a temp directory for the webapp if one is not already set
|
||||
resolveTempDirectory(context);
|
||||
|
||||
|
@ -192,20 +191,16 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
@Override
|
||||
public void deconfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
// delete temp directory if we had to create it or if it isn't called work
|
||||
Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
|
||||
|
||||
if (context.getTempDirectory()!=null && (tmpdirConfigured == null || !tmpdirConfigured.booleanValue()) && !isTempWorkDirectory(context.getTempDirectory()))
|
||||
//if we're not persisting the temp dir contents delete it
|
||||
if (!context.isPersistTempDirectory())
|
||||
{
|
||||
IO.delete(context.getTempDirectory());
|
||||
context.setTempDirectory(null);
|
||||
|
||||
//clear out the context attributes for the tmp dir only if we had to
|
||||
//create the tmp dir
|
||||
context.setAttribute(TEMPDIR_CONFIGURED, null);
|
||||
context.setAttribute(WebAppContext.TEMPDIR, null);
|
||||
}
|
||||
|
||||
|
||||
//if it wasn't explicitly configured by the user, then unset it
|
||||
Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
|
||||
if (tmpdirConfigured != null && !tmpdirConfigured)
|
||||
context.setTempDirectory(null);
|
||||
|
||||
//reset the base resource back to what it was before we did any unpacking of resources
|
||||
context.setBaseResource(_preUnpackBaseResource);
|
||||
|
@ -238,51 +233,44 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
* <p>A. Try to use an explicit directory specifically for this webapp:</p>
|
||||
* <ol>
|
||||
* <li>
|
||||
* Iff an explicit directory is set for this webapp, use it. Do NOT set
|
||||
* delete on exit.
|
||||
* Iff an explicit directory is set for this webapp, use it. Set delete on
|
||||
* exit depends on value of persistTempDirectory.
|
||||
* </li>
|
||||
* <li>
|
||||
* Iff javax.servlet.context.tempdir context attribute is set for
|
||||
* this webapp && exists && writeable, then use it. Do NOT set delete on exit.
|
||||
* this webapp && exists && writeable, then use it. Set delete on exit depends on
|
||||
* value of persistTempDirectory.
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>B. Create a directory based on global settings. The new directory
|
||||
* will be called "Jetty_"+host+"_"+port+"__"+context+"_"+virtualhost
|
||||
* Work out where to create this directory:
|
||||
* <ol>
|
||||
* <li>
|
||||
* Iff $(jetty.home)/work exists create the directory there. Do NOT
|
||||
* set delete on exit. Do NOT delete contents if dir already exists.
|
||||
* </li>
|
||||
* <li>
|
||||
* Iff WEB-INF/work exists create the directory there. Do NOT set
|
||||
* delete on exit. Do NOT delete contents if dir already exists.
|
||||
* </li>
|
||||
* <li>
|
||||
* Else create dir in $(java.io.tmpdir). Set delete on exit. Delete
|
||||
* contents if dir already exists.
|
||||
* </li>
|
||||
* </ol>
|
||||
* will be called "Jetty-"+host+"-"+port+"__"+context+"-"+virtualhost+"-"+randomdigits+".dir"
|
||||
* </p>
|
||||
* <p>
|
||||
* If the user has specified the context attribute org.eclipse.jetty.webapp.basetempdir, the
|
||||
* directory specified by this attribute will be the parent of the temp dir created. Otherwise,
|
||||
* the parent dir is $(java.io.tmpdir). Set delete on exit depends on value of persistTempDirectory.
|
||||
* </p>
|
||||
*/
|
||||
public void resolveTempDirectory (WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
//If a tmp directory is already set, we're done
|
||||
//If a tmp directory is already set we should use it
|
||||
File tmpDir = context.getTempDirectory();
|
||||
if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite())
|
||||
if (tmpDir != null)
|
||||
{
|
||||
context.setAttribute(TEMPDIR_CONFIGURED, Boolean.TRUE);
|
||||
return; // Already have a suitable tmp dir configured
|
||||
configureTempDirectory(tmpDir, context);
|
||||
context.setAttribute(TEMPDIR_CONFIGURED, Boolean.TRUE); //the tmp dir was set explicitly
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// No temp directory configured, try to establish one.
|
||||
// First we check the context specific, javax.servlet specified, temp directory attribute
|
||||
// No temp directory configured, try to establish one via the javax.servlet.context.tempdir.
|
||||
File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR));
|
||||
if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite())
|
||||
if (servletTmpDir != null)
|
||||
{
|
||||
// Use as tmpDir
|
||||
tmpDir = servletTmpDir;
|
||||
configureTempDirectory(tmpDir, context);
|
||||
// Ensure Attribute has File object
|
||||
context.setAttribute(WebAppContext.TEMPDIR,tmpDir);
|
||||
// Set as TempDir in context.
|
||||
|
@ -290,60 +278,25 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
return;
|
||||
}
|
||||
|
||||
try
|
||||
//We need to make a temp dir. Check if the user has set a directory to use instead
|
||||
//of java.io.tmpdir as the parent of the dir
|
||||
File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR));
|
||||
if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite())
|
||||
{
|
||||
// Put the tmp dir in the work directory if we had one
|
||||
File work = new File(System.getProperty("jetty.base"),"work");
|
||||
if (work.exists() && work.canWrite() && work.isDirectory())
|
||||
{
|
||||
makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists
|
||||
}
|
||||
else
|
||||
{
|
||||
File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR));
|
||||
if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite())
|
||||
{
|
||||
// Use baseTemp directory (allow the funky Jetty_0_0_0_0.. subdirectory logic to kick in
|
||||
makeTempDirectory(baseTemp,context,false);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true); //make a tmpdir, delete if it already exists
|
||||
}
|
||||
}
|
||||
//Make a temp directory as a child of the given base dir
|
||||
makeTempDirectory(baseTemp,context);
|
||||
}
|
||||
catch(Exception e)
|
||||
else
|
||||
{
|
||||
tmpDir=null;
|
||||
LOG.ignore(e);
|
||||
}
|
||||
|
||||
//Third ... Something went wrong trying to make the tmp directory, just make
|
||||
//a jvm managed tmp directory
|
||||
if (context.getTempDirectory() == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Last resort
|
||||
tmpDir=File.createTempFile("JettyContext","");
|
||||
if (tmpDir.exists())
|
||||
IO.delete(tmpDir);
|
||||
tmpDir.mkdir();
|
||||
tmpDir.deleteOnExit();
|
||||
context.setTempDirectory(tmpDir);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
tmpDir = null;
|
||||
throw new IllegalStateException("Cannot create tmp dir in "+System.getProperty("java.io.tmpdir")+ " for context "+context,e);
|
||||
}
|
||||
//Make a temp directory in java.io.tmpdir
|
||||
makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an Object, return File reference for object.
|
||||
* Typically used to convert anonymous Object from getAttribute() calls to a File object.
|
||||
* @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null)
|
||||
* @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null
|
||||
* @return the File object, null if null, or null if not a File or String
|
||||
*/
|
||||
private File asFile(Object fileattr)
|
||||
|
@ -365,45 +318,47 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
|
||||
|
||||
|
||||
public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
|
||||
throws IOException
|
||||
public void makeTempDirectory (File parent, WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
|
||||
if (parent == null || !parent.exists() || !parent.canWrite() || !parent.isDirectory())
|
||||
throw new IllegalStateException("Parent for temp dir not configured correctly: "+(parent==null?"null":"writeable="+parent.canWrite()));
|
||||
|
||||
String temp = getCanonicalNameForWebAppTmpDir(context);
|
||||
File tmpDir = File.createTempFile(temp, ".dir", parent);
|
||||
//delete the file that was created
|
||||
tmpDir.delete();
|
||||
//and make a directory of the same name
|
||||
tmpDir.mkdirs();
|
||||
configureTempDirectory(tmpDir, context);
|
||||
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("Set temp dir "+tmpDir);
|
||||
context.setTempDirectory(tmpDir);
|
||||
}
|
||||
|
||||
private void configureTempDirectory (File dir, WebAppContext context)
|
||||
{
|
||||
if (dir == null)
|
||||
throw new IllegalArgumentException("Null temp dir");
|
||||
|
||||
//if dir exists and we don't want it persisted, delete it
|
||||
if (dir.exists() && !context.isPersistTempDirectory())
|
||||
{
|
||||
String temp = getCanonicalNameForWebAppTmpDir(context);
|
||||
File tmpDir = new File(parent,temp);
|
||||
|
||||
if (deleteExisting && tmpDir.exists())
|
||||
{
|
||||
if (!IO.delete(tmpDir))
|
||||
{
|
||||
if(LOG.isDebugEnabled())LOG.debug("Failed to delete temp dir "+tmpDir);
|
||||
}
|
||||
|
||||
//If we can't delete the existing tmp dir, create a new one
|
||||
if (tmpDir.exists())
|
||||
{
|
||||
String old=tmpDir.toString();
|
||||
tmpDir=File.createTempFile(temp+"_","");
|
||||
if (tmpDir.exists())
|
||||
IO.delete(tmpDir);
|
||||
LOG.warn("Can't reuse "+old+", using "+tmpDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tmpDir.exists())
|
||||
tmpDir.mkdir();
|
||||
|
||||
//If the parent is not a work directory
|
||||
if (!isTempWorkDirectory(tmpDir))
|
||||
{
|
||||
tmpDir.deleteOnExit();
|
||||
}
|
||||
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("Set temp dir "+tmpDir);
|
||||
context.setTempDirectory(tmpDir);
|
||||
if (!IO.delete(dir))
|
||||
throw new IllegalStateException("Failed to delete temp dir "+dir);
|
||||
}
|
||||
|
||||
//if it doesn't exist make it
|
||||
if (!dir.exists())
|
||||
dir.mkdirs();
|
||||
|
||||
if (!context.isPersistTempDirectory())
|
||||
dir.deleteOnExit();
|
||||
|
||||
//is it useable
|
||||
if (!dir.canWrite() || !dir.isDirectory())
|
||||
throw new IllegalStateException("Temp dir "+dir+" not useable: writeable="+dir.canWrite()+", dir="+dir.isDirectory());
|
||||
}
|
||||
|
||||
|
||||
|
@ -566,45 +521,17 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
|
||||
|
||||
public File findWorkDirectory (WebAppContext context) throws IOException
|
||||
{
|
||||
if (context.getBaseResource() != null)
|
||||
{
|
||||
Resource web_inf = context.getWebInf();
|
||||
if (web_inf !=null && web_inf.exists())
|
||||
{
|
||||
return new File(web_inf.getFile(),"work");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the tmpDir itself is called "work", or if the tmpDir
|
||||
* is in a directory called "work".
|
||||
* @return true if File is a temporary or work directory
|
||||
*/
|
||||
public boolean isTempWorkDirectory (File tmpDir)
|
||||
{
|
||||
if (tmpDir == null)
|
||||
return false;
|
||||
if (tmpDir.getName().equalsIgnoreCase("work"))
|
||||
return true;
|
||||
File t = tmpDir.getParentFile();
|
||||
if (t == null)
|
||||
return false;
|
||||
return (t.getName().equalsIgnoreCase("work"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a canonical name for a webapp temp directory.
|
||||
* The form of the name is:
|
||||
* <code>"Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36_hashcode_of_whole_string</code>
|
||||
* <code>"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"</code>
|
||||
*
|
||||
* host and port uniquely identify the server
|
||||
* context and virtual host uniquely identify the webapp
|
||||
* randomdigits ensure every tmp directory is unique
|
||||
*
|
||||
* @return the canonical name for the webapp temp directory
|
||||
*/
|
||||
public static String getCanonicalNameForWebAppTmpDir (WebAppContext context)
|
||||
|
@ -697,6 +624,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
|
||||
canonicalName.append("-");
|
||||
|
||||
return canonicalName.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public class JettyAnnotatedEventDriver extends AbstractEventDriver
|
|||
}
|
||||
if (anno.maxBinaryMessageSize() > 0)
|
||||
{
|
||||
this.policy.setMaxTextMessageSize(anno.maxBinaryMessageSize());
|
||||
this.policy.setMaxBinaryMessageSize(anno.maxBinaryMessageSize());
|
||||
}
|
||||
if (anno.inputBufferSize() > 0)
|
||||
{
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.servlet;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.Extension;
|
||||
|
||||
/**
|
||||
* Abstract WebSocket creator interface.
|
||||
* <p>
|
||||
|
|
Loading…
Reference in New Issue