PR #12186 - Make HttpConnection internal and implement a public Upgrade interface

Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
This commit is contained in:
Lachlan Roberts 2024-08-29 11:44:15 +10:00
parent 594a65099c
commit b6f2c869e5
No known key found for this signature in database
GPG Key ID: 5663FB7A8FF7E348
29 changed files with 83 additions and 32 deletions

View File

@ -1865,7 +1865,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
}
});
// Close the parser to cause the issue.
org.eclipse.jetty.server.HttpConnection.getCurrentConnection().getParser().close();
org.eclipse.jetty.server.internal.HttpConnection.getCurrentConnection().getParser().close();
}
});
server.start();

View File

@ -455,12 +455,18 @@ public class HttpGenerator
}
}
public void servletUpgrade()
public void upgrade()
{
_noContentResponse = false;
_state = State.COMMITTED;
}
@Deprecated(since = "12.1.0", forRemoval = true)
public void servletUpgrade()
{
upgrade();
}
private void prepareChunk(ByteBuffer chunk, int remaining)
{
// if we need CRLF add this to header

View File

@ -2023,7 +2023,7 @@ public class HttpParser
_contentLength = -1;
}
@Deprecated
@Deprecated(since = "12.1.0", forRemoval = true)
public void servletUpgrade()
{
upgrade();

View File

@ -42,9 +42,9 @@ import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Utf8StringBuilder;

View File

@ -140,6 +140,11 @@ public interface Connection extends Closeable
void onUpgradeTo(ByteBuffer buffer);
}
interface Upgrade
{
void upgrade();
}
/**
* <p>A Listener for connection events.</p>
* <p>Listeners can be added to a {@link Connection} to get open and close events.

View File

@ -28,4 +28,5 @@ module org.eclipse.jetty.server
exports org.eclipse.jetty.server.jmx to
org.eclipse.jetty.jmx;
exports org.eclipse.jetty.server.internal;
}

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.QuotedCSVParser;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Index;

View File

@ -19,6 +19,7 @@ import org.eclipse.jetty.http.ComplianceViolation;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.annotation.Name;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.server;
package org.eclipse.jetty.server.internal;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -53,7 +53,16 @@ import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RetainableByteBuffer;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.server.internal.HttpChannelState;
import org.eclipse.jetty.server.AbstractMetaDataConnection;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.ConnectionMetaData;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpStream;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.TunnelSupport;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HostPort;
@ -71,7 +80,7 @@ import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
/**
* <p>A {@link Connection} that handles the HTTP protocol.</p>
*/
public class HttpConnection extends AbstractMetaDataConnection implements Runnable, Connection.UpgradeFrom, Connection.UpgradeTo, ConnectionMetaData
public class HttpConnection extends AbstractMetaDataConnection implements Runnable, Connection.UpgradeFrom, Connection.UpgradeTo, Connection.Upgrade, ConnectionMetaData
{
private static final Logger LOG = LoggerFactory.getLogger(HttpConnection.class);
private static final HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE, "h2c");
@ -326,6 +335,13 @@ public class HttpConnection extends AbstractMetaDataConnection implements Runnab
BufferUtil.append(getRequestBuffer(), buffer);
}
@Override
public void upgrade()
{
getParser().upgrade();
getGenerator().upgrade();
}
void releaseRequestBuffer()
{
if (_retainableByteBuffer != null && _retainableByteBuffer.isEmpty())

View File

@ -19,6 +19,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.BeforeEach;

View File

@ -25,6 +25,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ManagedSelector;
import org.eclipse.jetty.io.SocketChannelEndPoint;
import org.eclipse.jetty.server.internal.HttpChannelState;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.NanoTime;

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

View File

@ -46,6 +46,7 @@ import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.handler.DumpHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.NanoTime;

View File

@ -48,6 +48,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.handler.EchoHandler;
import org.eclipse.jetty.server.handler.HelloHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.internal.HttpChannelState;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Jetty;

View File

@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;

View File

@ -298,7 +298,7 @@ public class DelayedHandlerTest
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
new Throwable().printStackTrace(new PrintStream(out));
String stack = out.toString(StandardCharsets.ISO_8859_1);
assertThat(stack, containsString("org.eclipse.jetty.server.HttpConnection.onFillable"));
assertThat(stack, containsString("org.eclipse.jetty.server.internal.HttpConnection.onFillable"));
assertThat(stack, containsString("org.eclipse.jetty.server.handler.DelayedHandler.handle"));
// Check the content is available
@ -469,7 +469,7 @@ public class DelayedHandlerTest
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
new Throwable().printStackTrace(new PrintStream(out));
String stack = out.toString(StandardCharsets.ISO_8859_1);
assertThat(stack, containsString("org.eclipse.jetty.server.HttpConnection.onFillable"));
assertThat(stack, containsString("org.eclipse.jetty.server.internal.HttpConnection.onFillable"));
assertThat(stack, containsString("org.eclipse.jetty.server.handler.DelayedHandler.handle"));
Fields fields = FormFields.from(request).get(1, TimeUnit.NANOSECONDS);

View File

@ -494,8 +494,8 @@ public class SniSslConnectionFactoryTest
assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals(0, history.size());
}

View File

@ -178,8 +178,8 @@ public class SslConnectionFactoryTest
assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
assertEquals("customize connector class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals("customize http class org.eclipse.jetty.server.internal.HttpConnection,true", history.poll());
assertEquals(0, history.size());
}

View File

@ -24,7 +24,7 @@ import org.eclipse.jetty.http2.server.internal.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.quic.server.ServerQuicConnection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

View File

@ -78,6 +78,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.SetCookieParser;
import org.eclipse.jetty.http.pathmap.MatchedResource;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.security.AuthenticationState;
@ -85,7 +86,6 @@ import org.eclipse.jetty.security.UserIdentity;
import org.eclipse.jetty.server.ConnectionMetaData;
import org.eclipse.jetty.server.CookieCache;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.HttpCookieUtils;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
@ -951,13 +951,18 @@ public class ServletApiRequest implements HttpServletRequest
throw new ServletException("Unable to instantiate handler class", e);
}
HttpConnection httpConnection = (HttpConnection)_servletContextRequest.getConnectionMetaData().getConnection();
httpConnection.getParser().upgrade();
Connection connection = _servletContextRequest.getConnectionMetaData().getConnection();
if (connection instanceof Connection.Upgrade upgradeableConnection)
{
outputStream.flush(); // commit the 101 response
upgradeableConnection.upgrade();
}
else
{
LOG.warn("Unexpected connection type {}", connection);
throw new IllegalStateException();
}
AsyncContext asyncContext = forceStartAsync(); // force the servlet in async mode
outputStream.flush(); // commit the 101 response
httpConnection.getGenerator().servletUpgrade(); // tell the generator it can send data as-is
CompletableFuture.allOf(inputStreamComplete, outputStreamComplete).whenComplete((result, failure) ->
{
upgradeHandler.destroy();

View File

@ -44,10 +44,10 @@ import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;

View File

@ -78,6 +78,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.SetCookieParser;
import org.eclipse.jetty.http.pathmap.MatchedResource;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.security.AuthenticationState;
@ -85,7 +86,6 @@ import org.eclipse.jetty.security.UserIdentity;
import org.eclipse.jetty.server.ConnectionMetaData;
import org.eclipse.jetty.server.CookieCache;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.HttpCookieUtils;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
@ -951,13 +951,19 @@ public class ServletApiRequest implements HttpServletRequest
throw new ServletException("Unable to instantiate handler class", e);
}
HttpConnection httpConnection = (HttpConnection)_servletContextRequest.getConnectionMetaData().getConnection();
httpConnection.getParser().upgrade();
Connection connection = _servletContextRequest.getConnectionMetaData().getConnection();
if (connection instanceof Connection.Upgrade upgradeableConnection)
{
outputStream.flush(); // commit the 101 response
upgradeableConnection.upgrade();
}
else
{
LOG.warn("Unexpected connection type {}", connection);
throw new IllegalStateException();
}
AsyncContext asyncContext = forceStartAsync(); // force the servlet in async mode
outputStream.flush(); // commit the 101 response
httpConnection.getGenerator().servletUpgrade(); // tell the generator it can send data as-is
CompletableFuture.allOf(inputStreamComplete, outputStreamComplete).whenComplete((result, failure) ->
{
upgradeHandler.destroy();

View File

@ -44,10 +44,10 @@ import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
import org.eclipse.jetty.ee11.servlet.ServletContextRequest;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;

View File

@ -596,7 +596,7 @@ public class Request implements HttpServletRequest
* <dl>
* <dt>org.eclipse.jetty.server.Server</dt><dd>The Jetty Server instance</dd>
* <dt>org.eclipse.jetty.server.HttpChannel</dt><dd>The HttpChannel for this request</dd>
* <dt>org.eclipse.jetty.server.HttpConnection</dt><dd>The HttpConnection or null if another transport is used</dd>
* <dt>org.eclipse.jetty.server.internal.HttpConnection</dt><dd>The HttpConnection or null if another transport is used</dd>
* </dl>
* While these attributes may look like security problems, they are exposing nothing that is not already
* available via reflection from a Request instance.

View File

@ -41,10 +41,10 @@ import org.eclipse.jetty.ee9.nested.Request;
import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.internal.HttpConnection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;