484818 - Expose interesting HTTP/2 attributes and operations via JMX.
Initial work to expose already existing attributes on the client.
This commit is contained in:
parent
b7ab9e0a22
commit
14a3b2eab2
|
@ -29,6 +29,7 @@ import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
|
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
|
||||||
|
import org.eclipse.jetty.http2.FlowControlStrategy;
|
||||||
import org.eclipse.jetty.http2.api.Session;
|
import org.eclipse.jetty.http2.api.Session;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||||
|
@ -40,6 +41,8 @@ import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||||
import org.eclipse.jetty.io.SelectorManager;
|
import org.eclipse.jetty.io.SelectorManager;
|
||||||
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
@ -106,6 +109,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
* client.stop();
|
* client.stop();
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
|
@ManagedObject
|
||||||
public class HTTP2Client extends ContainerLifeCycle
|
public class HTTP2Client extends ContainerLifeCycle
|
||||||
{
|
{
|
||||||
private Executor executor;
|
private Executor executor;
|
||||||
|
@ -116,7 +120,10 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
private int selectors = 1;
|
private int selectors = 1;
|
||||||
private long idleTimeout = 30000;
|
private long idleTimeout = 30000;
|
||||||
private long connectTimeout = 10000;
|
private long connectTimeout = 10000;
|
||||||
|
private int inputBufferSize = 8192;
|
||||||
private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14");
|
private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14");
|
||||||
|
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
||||||
|
private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
|
@ -203,6 +210,7 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
this.connectionFactory = connectionFactory;
|
this.connectionFactory = connectionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The number of selectors")
|
||||||
public int getSelectors()
|
public int getSelectors()
|
||||||
{
|
{
|
||||||
return selectors;
|
return selectors;
|
||||||
|
@ -213,6 +221,7 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
this.selectors = selectors;
|
this.selectors = selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The idle timeout in milliseconds")
|
||||||
public long getIdleTimeout()
|
public long getIdleTimeout()
|
||||||
{
|
{
|
||||||
return idleTimeout;
|
return idleTimeout;
|
||||||
|
@ -223,6 +232,7 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
this.idleTimeout = idleTimeout;
|
this.idleTimeout = idleTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The connect timeout in milliseconds")
|
||||||
public long getConnectTimeout()
|
public long getConnectTimeout()
|
||||||
{
|
{
|
||||||
return connectTimeout;
|
return connectTimeout;
|
||||||
|
@ -236,6 +246,18 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
selector.setConnectTimeout(connectTimeout);
|
selector.setConnectTimeout(connectTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The size of the buffer used to read from the network")
|
||||||
|
public int getInputBufferSize()
|
||||||
|
{
|
||||||
|
return inputBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputBufferSize(int inputBufferSize)
|
||||||
|
{
|
||||||
|
this.inputBufferSize = inputBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The ALPN protocol list")
|
||||||
public List<String> getProtocols()
|
public List<String> getProtocols()
|
||||||
{
|
{
|
||||||
return protocols;
|
return protocols;
|
||||||
|
@ -246,6 +268,28 @@ public class HTTP2Client extends ContainerLifeCycle
|
||||||
this.protocols = protocols;
|
this.protocols = protocols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The initial size of session's flow control receive window")
|
||||||
|
public int getInitialSessionRecvWindow()
|
||||||
|
{
|
||||||
|
return initialSessionRecvWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
|
||||||
|
{
|
||||||
|
this.initialSessionRecvWindow = initialSessionRecvWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("The initial size of stream's flow control receive window")
|
||||||
|
public int getInitialStreamRecvWindow()
|
||||||
|
{
|
||||||
|
return initialStreamRecvWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialStreamRecvWindow(int initialStreamRecvWindow)
|
||||||
|
{
|
||||||
|
this.initialStreamRecvWindow = initialStreamRecvWindow;
|
||||||
|
}
|
||||||
|
|
||||||
public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise)
|
public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise)
|
||||||
{
|
{
|
||||||
connect(null, address, listener, promise);
|
connect(null, address, listener, promise);
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
|
@ -50,6 +51,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
|
public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
|
||||||
public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
|
public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
|
||||||
|
|
||||||
|
private final Connection.Listener connectionListener = new ConnectionListener();
|
||||||
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -67,7 +69,9 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
FlowControlStrategy flowControl = newFlowControlStrategy();
|
FlowControlStrategy flowControl = newFlowControlStrategy();
|
||||||
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
|
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
|
||||||
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
|
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
|
||||||
return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener);
|
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener);
|
||||||
|
connection.addListener(connectionListener);
|
||||||
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FlowControlStrategy newFlowControlStrategy()
|
protected FlowControlStrategy newFlowControlStrategy()
|
||||||
|
@ -75,11 +79,19 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
return new BufferingFlowControlStrategy(0.5F);
|
return new BufferingFlowControlStrategy(0.5F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link HTTP2Client#getInitialSessionRecvWindow()} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getInitialSessionRecvWindow()
|
public int getInitialSessionRecvWindow()
|
||||||
{
|
{
|
||||||
return initialSessionRecvWindow;
|
return initialSessionRecvWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link HTTP2Client#setInitialSessionRecvWindow(int)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
|
public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
|
||||||
{
|
{
|
||||||
this.initialSessionRecvWindow = initialSessionRecvWindow;
|
this.initialSessionRecvWindow = initialSessionRecvWindow;
|
||||||
|
@ -108,8 +120,14 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
|
|
||||||
PrefaceFrame prefaceFrame = new PrefaceFrame();
|
PrefaceFrame prefaceFrame = new PrefaceFrame();
|
||||||
SettingsFrame settingsFrame = new SettingsFrame(settings, false);
|
SettingsFrame settingsFrame = new SettingsFrame(settings, false);
|
||||||
|
|
||||||
ISession session = getSession();
|
ISession session = getSession();
|
||||||
int windowDelta = getInitialSessionRecvWindow() - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
|
||||||
|
int sessionRecv = client.getInitialSessionRecvWindow();
|
||||||
|
if (sessionRecv == FlowControlStrategy.DEFAULT_WINDOW_SIZE)
|
||||||
|
sessionRecv = initialSessionRecvWindow;
|
||||||
|
|
||||||
|
int windowDelta = sessionRecv - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
||||||
if (windowDelta > 0)
|
if (windowDelta > 0)
|
||||||
{
|
{
|
||||||
session.updateRecvWindow(windowDelta);
|
session.updateRecvWindow(windowDelta);
|
||||||
|
@ -138,4 +156,21 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
promise.failed(x);
|
promise.failed(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ConnectionListener implements Connection.Listener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onOpened(Connection connection)
|
||||||
|
{
|
||||||
|
HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
|
||||||
|
http2Connection.client.addManaged((LifeCycle)http2Connection.getSession());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClosed(Connection connection)
|
||||||
|
{
|
||||||
|
HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
|
||||||
|
http2Connection.client.removeBean(http2Connection.getSession());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client.http;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
|
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
|
||||||
|
@ -71,6 +72,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
|
||||||
client.setByteBufferPool(httpClient.getByteBufferPool());
|
client.setByteBufferPool(httpClient.getByteBufferPool());
|
||||||
client.setConnectTimeout(httpClient.getConnectTimeout());
|
client.setConnectTimeout(httpClient.getConnectTimeout());
|
||||||
client.setIdleTimeout(httpClient.getIdleTimeout());
|
client.setIdleTimeout(httpClient.getIdleTimeout());
|
||||||
|
client.setInputBufferSize(httpClient.getResponseBufferSize());
|
||||||
}
|
}
|
||||||
addBean(client);
|
addBean(client);
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
@ -160,6 +162,14 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
|
||||||
promise.failed(failure);
|
promise.failed(failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, Integer> onPreface(Session session)
|
||||||
|
{
|
||||||
|
Map<Integer, Integer> settings = new HashMap<>();
|
||||||
|
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow());
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettings(Session session, SettingsFrame frame)
|
public void onSettings(Session session, SettingsFrame frame)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue