Merge branch 'jetty-9.3.x'

This commit is contained in:
Joakim Erdfelt 2016-03-15 07:49:28 -07:00
commit dcfa0b8910
17 changed files with 125 additions and 194 deletions

View File

@ -300,25 +300,18 @@ public class HttpSenderOverHTTP extends HttpSender
} }
} }
private class ByteBufferRecyclerCallback implements Callback private class ByteBufferRecyclerCallback extends Callback.Nested
{ {
private final Callback callback;
private final ByteBufferPool pool; private final ByteBufferPool pool;
private final ByteBuffer[] buffers; private final ByteBuffer[] buffers;
private ByteBufferRecyclerCallback(Callback callback, ByteBufferPool pool, ByteBuffer... buffers) private ByteBufferRecyclerCallback(Callback callback, ByteBufferPool pool, ByteBuffer... buffers)
{ {
this.callback = callback; super(callback);
this.pool = pool; this.pool = pool;
this.buffers = buffers; this.buffers = buffers;
} }
@Override
public boolean isNonBlocking()
{
return callback.isNonBlocking();
}
@Override @Override
public void succeeded() public void succeeded()
{ {
@ -327,7 +320,7 @@ public class HttpSenderOverHTTP extends HttpSender
assert !buffer.hasRemaining(); assert !buffer.hasRemaining();
pool.release(buffer); pool.release(buffer);
} }
callback.succeeded(); super.succeeded();
} }
@Override @Override
@ -335,7 +328,7 @@ public class HttpSenderOverHTTP extends HttpSender
{ {
for (ByteBuffer buffer : buffers) for (ByteBuffer buffer : buffers)
pool.release(buffer); pool.release(buffer);
callback.failed(x); super.failed(x);
} }
} }
} }

View File

@ -217,11 +217,6 @@ public class DeferredContentProvider implements AsyncContentProvider, Callback,
return closed.get(); return closed.get();
} }
@Override
public void succeeded()
{
}
@Override @Override
public void failed(Throwable failure) public void failed(Throwable failure)
{ {

View File

@ -136,11 +136,6 @@ public class InputStreamContentProvider implements ContentProvider, Callback, Cl
} }
} }
@Override
public void succeeded()
{
}
@Override @Override
public void failed(Throwable failure) public void failed(Throwable failure)
{ {

View File

@ -36,7 +36,6 @@ public class HttpTransportOverFCGI implements HttpTransport
private final ServerGenerator generator; private final ServerGenerator generator;
private final Flusher flusher; private final Flusher flusher;
private final int request; private final int request;
private volatile boolean head;
private volatile boolean shutdown; private volatile boolean shutdown;
private volatile boolean aborted; private volatile boolean aborted;
@ -98,7 +97,6 @@ public class HttpTransportOverFCGI implements HttpTransport
private void commit(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) private void commit(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
{ {
this.head = head;
boolean shutdown = this.shutdown = info.getFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); boolean shutdown = this.shutdown = info.getFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
if (head) if (head)

View File

@ -290,18 +290,17 @@ public class HTTP2Flusher extends IteratingCallback
entry.failed(failure); entry.failed(failure);
} }
public static abstract class Entry implements Callback public static abstract class Entry extends Callback.Nested
{ {
protected final Frame frame; protected final Frame frame;
protected final IStream stream; protected final IStream stream;
protected final Callback callback;
private boolean reset; private boolean reset;
protected Entry(Frame frame, IStream stream, Callback callback) protected Entry(Frame frame, IStream stream, Callback callback)
{ {
super(callback);
this.frame = frame; this.frame = frame;
this.stream = stream; this.stream = stream;
this.callback = callback;
} }
public int dataRemaining() public int dataRemaining()
@ -327,7 +326,7 @@ public class HTTP2Flusher extends IteratingCallback
stream.close(); stream.close();
stream.getSession().removeStream(stream); stream.getSession().removeStream(stream);
} }
callback.failed(x); super.failed(x);
} }
private boolean reset() private boolean reset()

View File

@ -1139,7 +1139,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
break; break;
} }
} }
callback.succeeded(); super.succeeded();
} }
} }
@ -1202,7 +1202,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
// and eventually remove the stream. // and eventually remove the stream.
if (stream.updateClose(dataFrame.isEndStream(), true)) if (stream.updateClose(dataFrame.isEndStream(), true))
removeStream(stream); removeStream(stream);
callback.succeeded(); super.succeeded();
} }
} }
} }

View File

@ -110,26 +110,20 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
copy.put(original); copy.put(original);
BufferUtil.flipToFlush(copy, 0); BufferUtil.flipToFlush(copy, 0);
Callback delegate = new Callback() Callback delegate = new Callback.Nested(callback)
{ {
@Override
public boolean isNonBlocking()
{
return callback.isNonBlocking();
}
@Override @Override
public void succeeded() public void succeeded()
{ {
byteBufferPool.release(copy); byteBufferPool.release(copy);
callback.succeeded(); super.succeeded();
} }
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
{ {
byteBufferPool.release(copy); byteBufferPool.release(copy);
callback.failed(x); super.failed(x);
} }
}; };

View File

@ -1,68 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.http2.server;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback;
public class ByteBufferCallback implements Callback
{
private final ByteBufferPool byteBufferPool;
private final ByteBuffer buffer;
private final Callback callback;
public ByteBufferCallback(ByteBufferPool byteBufferPool, ByteBuffer buffer, Callback callback)
{
this.byteBufferPool = byteBufferPool;
this.buffer = buffer;
this.callback = callback;
}
@Override
public boolean isNonBlocking()
{
return callback.isNonBlocking();
}
public ByteBuffer getByteBuffer()
{
return buffer;
}
@Override
public void succeeded()
{
recycle();
callback.succeeded();
}
@Override
public void failed(Throwable x)
{
recycle();
callback.failed(x);
}
private void recycle()
{
byteBufferPool.release(buffer);
}
}

View File

@ -304,11 +304,6 @@ public class SslConnection extends AbstractConnection
failedCallback(new Callback() failedCallback(new Callback()
{ {
@Override
public void succeeded()
{
}
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
{ {
@ -316,7 +311,6 @@ public class SslConnection extends AbstractConnection
getFillInterest().onFail(x); getFillInterest().onFail(x);
getWriteFlusher().onFail(x); getWriteFlusher().onFail(x);
} }
},x); },x);
} }
}; };

View File

@ -178,18 +178,12 @@ public class ProxyServlet extends AbstractProxyServlet
offset = 0; offset = 0;
} }
onResponseContent(request, response, proxyResponse, buffer, offset, length, new Callback() onResponseContent(request, response, proxyResponse, buffer, offset, length, new Callback.Nested(callback)
{ {
@Override
public void succeeded()
{
callback.succeeded();
}
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
{ {
callback.failed(x); super.failed(x);
proxyResponse.abort(x); proxyResponse.abort(x);
} }
}); });

View File

@ -24,7 +24,6 @@ import static javax.servlet.RequestDispatcher.ERROR_STATUS_CODE;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -709,25 +708,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_transport.abort(failure); _transport.abort(failure);
} }
private class CommitCallback implements Callback private class CommitCallback extends Callback.Nested
{ {
private final Callback _callback;
private CommitCallback(Callback callback) private CommitCallback(Callback callback)
{ {
_callback = callback; super(callback);
}
@Override
public boolean isNonBlocking()
{
return _callback.isNonBlocking();
}
@Override
public void succeeded()
{
_callback.succeeded();
} }
@Override @Override
@ -738,12 +723,12 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (x instanceof BadMessageException) if (x instanceof BadMessageException)
{ {
_transport.send(HttpGenerator.RESPONSE_500_INFO, false, null, true, new Callback() _transport.send(HttpGenerator.RESPONSE_500_INFO, false, null, true, new Callback.Nested(this)
{ {
@Override @Override
public void succeeded() public void succeeded()
{ {
_callback.failed(x); super.failed(x);
_response.getHttpOutput().closed(); _response.getHttpOutput().closed();
} }
@ -751,14 +736,14 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
public void failed(Throwable th) public void failed(Throwable th)
{ {
_transport.abort(x); _transport.abort(x);
_callback.failed(x); super.failed(x);
} }
}); });
} }
else else
{ {
_transport.abort(x); _transport.abort(x);
_callback.failed(x); super.failed(x);
} }
} }
} }

View File

@ -695,20 +695,20 @@ public class HttpOutput extends ServletOutputStream implements Runnable
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("sendContent(buffer={},{})",BufferUtil.toDetailString(content),callback); LOG.debug("sendContent(buffer={},{})",BufferUtil.toDetailString(content),callback);
write(content, true, new Callback() write(content, true, new Callback.Nested(callback)
{ {
@Override @Override
public void succeeded() public void succeeded()
{ {
closed(); closed();
callback.succeeded(); super.succeeded();
} }
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
{ {
abort(x); abort(x);
callback.failed(x); super.failed(x);
} }
}); });
} }

View File

@ -32,7 +32,9 @@ public interface Callback
* Instance of Adapter that can be used when the callback methods need an empty * Instance of Adapter that can be used when the callback methods need an empty
* implementation without incurring in the cost of allocating a new Adapter object. * implementation without incurring in the cost of allocating a new Adapter object.
*/ */
Callback NOOP = new Callback(){}; static Callback NOOP = new Callback(){};
};
/** /**
* <p>Callback invoked when the operation completes.</p> * <p>Callback invoked when the operation completes.</p>
@ -40,14 +42,16 @@ public interface Callback
* @see #failed(Throwable) * @see #failed(Throwable)
*/ */
default void succeeded() default void succeeded()
{} {
}
/** /**
* <p>Callback invoked when the operation fails.</p> * <p>Callback invoked when the operation fails.</p>
* @param x the reason for the operation failure * @param x the reason for the operation failure
*/ */
default void failed(Throwable x) default void failed(Throwable x)
{} {
}
/** /**
* @return True if the callback is known to never block the caller * @return True if the callback is known to never block the caller
@ -119,6 +123,38 @@ public interface Callback
} }
} }
class Nested implements Callback
{
private final Callback callback;
public Nested(Callback callback)
{
this.callback = callback;
}
public Nested(Nested nested)
{
this.callback = nested.callback;
}
@Override
public void succeeded()
{
callback.succeeded();
}
@Override
public void failed(Throwable x)
{
callback.failed(x);
}
@Override
public boolean isNonBlocking()
{
return callback.isNonBlocking();
}
}
/** /**
* <p>A CompletableFuture that is also a Callback.</p> * <p>A CompletableFuture that is also a Callback.</p>
*/ */

View File

@ -38,14 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* } * }
* </pre> * </pre>
*/ */
public class CountingCallback implements Callback public class CountingCallback extends Callback.Nested
{ {
private final Callback callback;
private final AtomicInteger count; private final AtomicInteger count;
public CountingCallback(Callback callback, int count) public CountingCallback(Callback callback, int count)
{ {
this.callback = callback; super(callback);
this.count = new AtomicInteger(count); this.count = new AtomicInteger(count);
} }
@ -64,7 +63,7 @@ public class CountingCallback implements Callback
if (count.compareAndSet(current, current - 1)) if (count.compareAndSet(current, current - 1))
{ {
if (current == 1) if (current == 1)
callback.succeeded(); super.succeeded();
return; return;
} }
} }
@ -84,7 +83,7 @@ public class CountingCallback implements Callback
if (count.compareAndSet(current, 0)) if (count.compareAndSet(current, 0))
{ {
callback.failed(failure); super.failed(failure);
return; return;
} }
} }

View File

@ -27,7 +27,6 @@ import java.util.Map;
import javax.websocket.Extension; import javax.websocket.Extension;
import javax.websocket.Extension.Parameter; import javax.websocket.Extension.Parameter;
import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;
import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.http.pathmap.PathSpec;
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
@ -63,8 +62,8 @@ public class JsrCreator implements WebSocketCreator
@Override @Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{ {
JsrHandshakeRequest hsreq = new JsrHandshakeRequest(req); JsrHandshakeRequest jsrHandshakeRequest = new JsrHandshakeRequest(req);
JsrHandshakeResponse hsresp = new JsrHandshakeResponse(resp); JsrHandshakeResponse jsrHandshakeResponse = new JsrHandshakeResponse(resp);
// Get raw config, as defined when the endpoint was added to the container // Get raw config, as defined when the endpoint was added to the container
ServerEndpointConfig config = metadata.getConfig(); ServerEndpointConfig config = metadata.getConfig();
@ -85,10 +84,7 @@ public class JsrCreator implements WebSocketCreator
// Get Configurator from config object (not guaranteed to be unique per endpoint upgrade) // Get Configurator from config object (not guaranteed to be unique per endpoint upgrade)
ServerEndpointConfig.Configurator configurator = config.getConfigurator(); ServerEndpointConfig.Configurator configurator = config.getConfigurator();
// modify handshake // [JSR] Step 1: check origin
configurator.modifyHandshake(config,hsreq,hsresp);
// check origin
if (!configurator.checkOrigin(req.getOrigin())) if (!configurator.checkOrigin(req.getOrigin()))
{ {
try try
@ -103,7 +99,7 @@ public class JsrCreator implements WebSocketCreator
return null; return null;
} }
// deal with sub protocols // [JSR] Step 2: deal with sub protocols
List<String> supported = config.getSubprotocols(); List<String> supported = config.getSubprotocols();
List<String> requested = req.getSubProtocols(); List<String> requested = req.getSubProtocols();
String subprotocol = configurator.getNegotiatedSubprotocol(supported,requested); String subprotocol = configurator.getNegotiatedSubprotocol(supported,requested);
@ -112,22 +108,22 @@ public class JsrCreator implements WebSocketCreator
resp.setAcceptedSubProtocol(subprotocol); resp.setAcceptedSubProtocol(subprotocol);
} }
// deal with extensions // [JSR] Step 3: deal with extensions
List<Extension> installedExts = new ArrayList<>(); List<Extension> installedExtensions = new ArrayList<>();
for (String extName : extensionFactory.getAvailableExtensions().keySet()) for (String extName : extensionFactory.getAvailableExtensions().keySet())
{ {
installedExts.add(new JsrExtension(extName)); installedExtensions.add(new JsrExtension(extName));
} }
List<Extension> requestedExts = new ArrayList<>(); List<Extension> requestedExts = new ArrayList<>();
for (ExtensionConfig reqCfg : req.getExtensions()) for (ExtensionConfig reqCfg : req.getExtensions())
{ {
requestedExts.add(new JsrExtension(reqCfg)); requestedExts.add(new JsrExtension(reqCfg));
} }
List<Extension> usedExts = configurator.getNegotiatedExtensions(installedExts,requestedExts); List<Extension> usedExtensions = configurator.getNegotiatedExtensions(installedExtensions,requestedExts);
List<ExtensionConfig> configs = new ArrayList<>(); List<ExtensionConfig> configs = new ArrayList<>();
if (usedExts != null) if (usedExtensions != null)
{ {
for (Extension used : usedExts) for (Extension used : usedExtensions)
{ {
ExtensionConfig ecfg = new ExtensionConfig(used.getName()); ExtensionConfig ecfg = new ExtensionConfig(used.getName());
for (Parameter param : used.getParameters()) for (Parameter param : used.getParameters())
@ -139,15 +135,8 @@ public class JsrCreator implements WebSocketCreator
} }
resp.setExtensions(configs); resp.setExtensions(configs);
// create endpoint class // [JSR] Step 4: build out new ServerEndpointConfig
try PathSpec pathSpec = jsrHandshakeRequest.getRequestPathSpec();
{
Class<?> endpointClass = config.getEndpointClass();
Configurator configr = config.getConfigurator();
Object endpoint = configr.getEndpointInstance(endpointClass);
// Do not decorate here (let the Connection and Session start first)
// This will allow CDI to see Session for injection into Endpoint classes.
PathSpec pathSpec = hsreq.getRequestPathSpec();
if (pathSpec instanceof UriTemplatePathSpec) if (pathSpec instanceof UriTemplatePathSpec)
{ {
// We have a PathParam path spec // We have a PathParam path spec
@ -156,6 +145,17 @@ public class JsrCreator implements WebSocketCreator
// Wrap the config with the path spec information // Wrap the config with the path spec information
config = new PathParamServerEndpointConfig(containerScope,config,wspathSpec,requestPath); config = new PathParamServerEndpointConfig(containerScope,config,wspathSpec,requestPath);
} }
// [JSR] Step 5: Call modifyHandshake
configurator.modifyHandshake(config,jsrHandshakeRequest,jsrHandshakeResponse);
try
{
// [JSR] Step 6: create endpoint class
Class<?> endpointClass = config.getEndpointClass();
Object endpoint = config.getConfigurator().getEndpointInstance(endpointClass);
// Do not decorate here (let the Connection and Session start first)
// This will allow CDI to see Session for injection into Endpoint classes.
return new EndpointInstance(endpoint,config,metadata); return new EndpointInstance(endpoint,config,metadata);
} }
catch (InstantiationException e) catch (InstantiationException e)

View File

@ -332,10 +332,12 @@ public class ContinuationsTest
{ {
Server server = new Server(); Server server = new Server();
try { try
{
ServerConnector connector = new ServerConnector(server); ServerConnector connector = new ServerConnector(server);
server.addConnector(connector); server.addConnector(connector);
if(log != null) { if(log != null)
{
log.clear(); log.clear();
} }
history.clear(); history.clear();
@ -370,7 +372,9 @@ public class ContinuationsTest
socket.getOutputStream().flush(); socket.getOutputStream().flush();
return toString(socket.getInputStream()); return toString(socket.getInputStream());
} }
} finally { }
finally
{
server.stop(); server.stop();
if (log != null) if (log != null)
@ -640,7 +644,8 @@ public class ContinuationsTest
{ {
private final List<String> log; private final List<String> log;
public Log(List<String> log) { public Log(List<String> log)
{
this.log = log; this.log = log;
} }

View File

@ -32,6 +32,7 @@ import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.test.support.StringUtil; import org.eclipse.jetty.test.support.StringUtil;
@ -41,6 +42,9 @@ import org.eclipse.jetty.test.support.rawhttp.HttpTesting;
import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.StringAssert; import org.eclipse.jetty.toolchain.test.StringAssert;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
@ -1444,6 +1448,9 @@ public abstract class RFC2616BaseTest
public void test14_23_IncompleteHostHeader() throws Exception public void test14_23_IncompleteHostHeader() throws Exception
{ {
// HTTP/1.1 - Incomplete (empty) Host header // HTTP/1.1 - Incomplete (empty) Host header
try
{
((StdErrLog)Log.getLogger(HttpParser.class)).setHideStacks(true);
StringBuffer req4 = new StringBuffer(); StringBuffer req4 = new StringBuffer();
req4.append("GET /tests/R1.txt HTTP/1.1\n"); req4.append("GET /tests/R1.txt HTTP/1.1\n");
@ -1454,6 +1461,11 @@ public abstract class RFC2616BaseTest
HttpTester.Response response = http.request(req4); HttpTester.Response response = http.request(req4);
assertEquals("14.23 HTTP/1.1 - Empty Host", HttpStatus.BAD_REQUEST_400, response.getStatus()); assertEquals("14.23 HTTP/1.1 - Empty Host", HttpStatus.BAD_REQUEST_400, response.getStatus());
} }
finally
{
((StdErrLog)Log.getLogger(HttpParser.class)).setHideStacks(false);
}
}
/** /**
* Tests the (byte) "Range" header for partial content. * Tests the (byte) "Range" header for partial content.