diff --git a/runtime/impl/src/main/java/com/google/apphosting/runtime/AppEngineConstants.java b/runtime/impl/src/main/java/com/google/apphosting/runtime/AppEngineConstants.java index 20758ff75..d32e5c3d0 100644 --- a/runtime/impl/src/main/java/com/google/apphosting/runtime/AppEngineConstants.java +++ b/runtime/impl/src/main/java/com/google/apphosting/runtime/AppEngineConstants.java @@ -20,6 +20,16 @@ /** {@code AppEngineConstants} centralizes some constants that are specific to our use of Jetty. */ public final class AppEngineConstants { + + /** + * If Legacy Mode is turned on, then Jetty is configured to be more forgiving of bad requests and + * to act more in the style of Jetty-9.3 + */ + public static final boolean LEGACY_MODE = + Boolean.getBoolean("com.google.apphosting.runtime.jetty94.LEGACY_MODE"); + + public static final String GAE_RUNTIME = System.getenv("GAE_RUNTIME"); + /** * This {@code ServletContext} attribute contains the {@link AppVersion} for the current * application. diff --git a/runtime/impl/src/main/java/com/google/apphosting/runtime/RequestRunner.java b/runtime/impl/src/main/java/com/google/apphosting/runtime/RequestRunner.java index f659142cf..166c7fc8f 100644 --- a/runtime/impl/src/main/java/com/google/apphosting/runtime/RequestRunner.java +++ b/runtime/impl/src/main/java/com/google/apphosting/runtime/RequestRunner.java @@ -16,6 +16,7 @@ package com.google.apphosting.runtime; +import static com.google.apphosting.runtime.AppEngineConstants.GAE_RUNTIME; import static java.util.concurrent.TimeUnit.MILLISECONDS; import com.google.appengine.api.ThreadManager; @@ -240,7 +241,7 @@ private void dispatchBackgroundRequest() throws InterruptedException, TimeoutExc String requestId = getBackgroundRequestId(upRequest); // For java21 runtime, RPC path, do the new background thread handling for now, and keep it for // other runtimes. - if (!Objects.equals(System.getenv("GAE_RUNTIME"), "java21")) { + if (!Objects.equals(GAE_RUNTIME, "java21")) { // Wait here for synchronization with the ThreadFactory. CountDownLatch latch = ThreadGroupPool.resetCurrentThread(); Thread thread = new ThreadProxy(); diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/AppVersionHandlerFactory.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/AppVersionHandlerFactory.java index b85e50e3b..c616bc219 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/AppVersionHandlerFactory.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/AppVersionHandlerFactory.java @@ -22,11 +22,28 @@ import org.eclipse.jetty.server.Server; public interface AppVersionHandlerFactory { + + enum EEVersion + { + EE8, + EE10 + } + + static EEVersion getEEVersion() { + if (Boolean.getBoolean("appengine.use.EE10")) + return EEVersion.EE10; + else + return EEVersion.EE8; + } + static AppVersionHandlerFactory newInstance(Server server, String serverInfo) { - if (Boolean.getBoolean("appengine.use.EE10")) { - return new EE10AppVersionHandlerFactory(server, serverInfo); - } else { - return new EE8AppVersionHandlerFactory(server, serverInfo); + switch (getEEVersion()) { + case EE10: + return new EE10AppVersionHandlerFactory(server, serverInfo); + case EE8: + return new EE8AppVersionHandlerFactory(server, serverInfo); + default: + throw new IllegalStateException("Unknown EE version: " + getEEVersion()); } } diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java index 129da7f33..d4e54a72d 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java @@ -15,8 +15,10 @@ */ package com.google.apphosting.runtime.jetty; +import static com.google.apphosting.runtime.AppEngineConstants.GAE_RUNTIME; import static com.google.apphosting.runtime.AppEngineConstants.HTTP_CONNECTOR_MODE; import static com.google.apphosting.runtime.AppEngineConstants.IGNORE_RESPONSE_SIZE_LIMIT; +import static com.google.apphosting.runtime.AppEngineConstants.LEGACY_MODE; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.apphosting.api.ApiProxy; @@ -45,14 +47,13 @@ import java.util.Objects; import java.util.concurrent.ExecutionException; import org.eclipse.jetty.http.CookieCompliance; +import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.MultiPartCompliance; import org.eclipse.jetty.http.UriCompliance; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SizeLimitHandler; +import org.eclipse.jetty.server.handler.SizeLimitHandler; import org.eclipse.jetty.util.VirtualThreads; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.util.resource.ResourceFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; /** @@ -65,13 +66,6 @@ public class JettyServletEngineAdapter implements ServletEngineAdapter { private static final int MAX_THREAD_POOL_THREADS = 100; private static final long MAX_RESPONSE_SIZE = 32 * 1024 * 1024; - /** - * If Legacy Mode is turned on, then Jetty is configured to be more forgiving of bad requests and - * to act more in the style of Jetty-9.3 - */ - public static final boolean LEGACY_MODE = - Boolean.getBoolean("com.google.apphosting.runtime.jetty94.LEGACY_MODE"); - private AppVersionKey lastAppVersionKey; static { @@ -108,7 +102,7 @@ public void start(String serverInfo, ServletEngineAdapter.Config runtimeOptions) new QueuedThreadPool(MAX_THREAD_POOL_THREADS, MIN_THREAD_POOL_THREADS); // Try to enable virtual threads if requested and on java21: if (Boolean.getBoolean("appengine.use.virtualthreads") - && "java21".equals(System.getenv("GAE_RUNTIME"))) { + && "java21".equals(GAE_RUNTIME)) { threadPool.setVirtualThreadsExecutor(VirtualThreads.getDefaultVirtualThreadsExecutor()); logger.atInfo().log("Configuring Appengine web server virtual threads."); } @@ -138,10 +132,18 @@ public void run(Runnable runnable) { httpConfiguration.setSendDateHeader(false); httpConfiguration.setSendServerVersion(false); httpConfiguration.setSendXPoweredBy(false); + + // If runtime is using EE8, then set URI compliance to LEGACY to behave like Jetty 9.4. + if (Objects.equals(AppVersionHandlerFactory.getEEVersion(), AppVersionHandlerFactory.EEVersion.EE8)) { + httpConfiguration.setUriCompliance(UriCompliance.LEGACY); + } + if (LEGACY_MODE) { + httpConfiguration.setUriCompliance(UriCompliance.LEGACY); + httpConfiguration.setHttpCompliance(HttpCompliance.RFC7230_LEGACY); httpConfiguration.setRequestCookieCompliance(CookieCompliance.RFC2965); httpConfiguration.setResponseCookieCompliance(CookieCompliance.RFC2965); - httpConfiguration.setUriCompliance(UriCompliance.LEGACY); + httpConfiguration.setMultiPartCompliance(MultiPartCompliance.LEGACY); } server.addConnector(rpcConnector); diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/delegate/impl/DelegateRpcExchange.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/delegate/impl/DelegateRpcExchange.java index 57c39d21c..afee2b2f4 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/delegate/impl/DelegateRpcExchange.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/delegate/impl/DelegateRpcExchange.java @@ -16,6 +16,8 @@ package com.google.apphosting.runtime.jetty.delegate.impl; +import static com.google.apphosting.runtime.AppEngineConstants.LEGACY_MODE; + import com.google.apphosting.base.protos.HttpPb; import com.google.apphosting.base.protos.HttpPb.ParsedHttpHeader; import com.google.apphosting.base.protos.RuntimePb; @@ -23,26 +25,23 @@ import com.google.apphosting.runtime.jetty.delegate.api.DelegateExchange; import com.google.common.base.Ascii; import com.google.protobuf.ByteString; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.io.ByteBufferAccumulator; -import org.eclipse.jetty.io.Content; -import org.eclipse.jetty.util.Attributes; -import org.eclipse.jetty.util.Callback; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.io.ByteBufferAccumulator; +import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.util.Attributes; +import org.eclipse.jetty.util.Callback; public class DelegateRpcExchange implements DelegateExchange { private static final Content.Chunk EOF = Content.Chunk.EOF; private static final String X_GOOGLE_INTERNAL_SKIPADMINCHECK = "x-google-internal-skipadmincheck"; private static final String SKIP_ADMIN_CHECK_ATTR = "com.google.apphosting.internal.SkipAdminCheck"; - static final boolean LEGACY_MODE = - Boolean.getBoolean("com.google.apphosting.runtime.jetty94.LEGACY_MODE"); private final HttpPb.HttpRequest _request; private final AtomicReference _content = new AtomicReference<>(); diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java index e4b59617f..42d9391f9 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java @@ -21,6 +21,7 @@ import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiProxy.LogRecord; +import com.google.apphosting.runtime.AppEngineConstants; import com.google.apphosting.runtime.jetty.EE10AppEngineAuthentication; import com.google.apphosting.utils.servlet.ee10.DeferredTaskServlet; import com.google.apphosting.utils.servlet.ee10.JdbcMySqlConnectionCleanupFilter; @@ -278,6 +279,9 @@ public boolean handle(Request request, Response response, Callback callback) thr protected ServletHandler newServletHandler() { ServletHandler handler = new ServletHandler(); handler.setAllowDuplicateMappings(true); + if (AppEngineConstants.LEGACY_MODE) { + handler.setDecodeAmbiguousURIs(true); + } return handler; } diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/proxy/JettyHttpProxy.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/proxy/JettyHttpProxy.java index 24f8bce26..a913f4b69 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/proxy/JettyHttpProxy.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/proxy/JettyHttpProxy.java @@ -20,21 +20,24 @@ import com.google.apphosting.base.protos.RuntimePb; import com.google.apphosting.base.protos.RuntimePb.UPRequest; import com.google.apphosting.base.protos.RuntimePb.UPResponse; +import com.google.apphosting.runtime.AppEngineConstants; import com.google.apphosting.runtime.LocalRpcContext; import com.google.apphosting.runtime.ServletEngineAdapter; import com.google.apphosting.runtime.anyrpc.EvaluationRuntimeServerInterface; import com.google.apphosting.runtime.jetty.AppInfoFactory; -import com.google.apphosting.runtime.jetty.JettyServletEngineAdapter; +import com.google.apphosting.runtime.jetty.AppVersionHandlerFactory; import com.google.common.base.Ascii; import com.google.common.base.Throwables; import com.google.common.flogger.GoogleLogger; import com.google.common.primitives.Ints; import java.time.Duration; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import org.eclipse.jetty.http.CookieCompliance; import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.MultiPartCompliance; import org.eclipse.jetty.http.UriCompliance; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; @@ -47,8 +50,6 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.util.Callback; -import static com.google.apphosting.runtime.AppEngineConstants.IGNORE_RESPONSE_SIZE_LIMIT; - /** * A Jetty web server handling HTTP requests on a given port and forwarding them via gRPC to the * Java8 App Engine runtime implementation. The deployed application is assumed to be located in a @@ -95,11 +96,18 @@ public static ServerConnector newConnector( HttpConfiguration config = connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration(); - if (JettyServletEngineAdapter.LEGACY_MODE) { + + // If runtime is using EE8, then set URI compliance to LEGACY to behave like Jetty 9.4. + if (Objects.equals(AppVersionHandlerFactory.getEEVersion(), AppVersionHandlerFactory.EEVersion.EE8)) { + config.setUriCompliance(UriCompliance.LEGACY); + } + + if (AppEngineConstants.LEGACY_MODE) { + config.setUriCompliance(UriCompliance.LEGACY); config.setHttpCompliance(HttpCompliance.RFC7230_LEGACY); config.setRequestCookieCompliance(CookieCompliance.RFC2965); config.setResponseCookieCompliance(CookieCompliance.RFC2965); - config.setUriCompliance(UriCompliance.LEGACY); + config.setMultiPartCompliance(MultiPartCompliance.LEGACY); } config.setRequestHeaderSize(runtimeOptions.jettyRequestHeaderSize()); diff --git a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/AppEngineWebAppContext.java b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/AppEngineWebAppContext.java index 52608a60d..8fb0866f8 100644 --- a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/AppEngineWebAppContext.java +++ b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/AppEngineWebAppContext.java @@ -16,6 +16,7 @@ package com.google.apphosting.runtime.jetty9; +import static com.google.apphosting.runtime.AppEngineConstants.GAE_RUNTIME; import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; import static java.nio.charset.StandardCharsets.UTF_8; @@ -79,8 +80,7 @@ public class AppEngineWebAppContext extends WebAppContext { private static final int MAX_RESPONSE_SIZE = 32 * 1024 * 1024; private static final boolean APP_IS_ASYNC = Boolean.getBoolean(RpcConnection.ASYNC_ENABLE_PPROPERTY); - private static final boolean IS_JAVA_8_RUNTIME = - Objects.equals(System.getenv("GAE_RUNTIME"), "java8"); + private static final boolean IS_JAVA_8_RUNTIME = Objects.equals(GAE_RUNTIME, "java8"); private static final ImmutableSet EMPTY_SET = ImmutableSet.builder().build(); diff --git a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyHttpProxy.java b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyHttpProxy.java index cb1768b06..226bd7a27 100644 --- a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyHttpProxy.java +++ b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyHttpProxy.java @@ -16,6 +16,8 @@ package com.google.apphosting.runtime.jetty9; +import static com.google.apphosting.runtime.AppEngineConstants.LEGACY_MODE; + import com.google.apphosting.base.protos.AppLogsPb; import com.google.apphosting.base.protos.RuntimePb; import com.google.apphosting.base.protos.RuntimePb.UPRequest; @@ -93,7 +95,7 @@ public static ServerConnector newConnector( HttpConnectionFactory factory = connector.getConnectionFactory(HttpConnectionFactory.class); factory.setHttpCompliance( - RpcConnector.LEGACY_MODE ? HttpCompliance.RFC7230_LEGACY : HttpCompliance.RFC7230); + LEGACY_MODE ? HttpCompliance.RFC7230_LEGACY : HttpCompliance.RFC7230); HttpConfiguration config = factory.getHttpConfiguration(); config.setRequestHeaderSize(runtimeOptions.jettyRequestHeaderSize()); diff --git a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyServletEngineAdapter.java b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyServletEngineAdapter.java index 97ddcc7c5..629a8c19d 100644 --- a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyServletEngineAdapter.java +++ b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyServletEngineAdapter.java @@ -16,6 +16,7 @@ package com.google.apphosting.runtime.jetty9; +import static com.google.apphosting.runtime.AppEngineConstants.GAE_RUNTIME; import static com.google.apphosting.runtime.AppEngineConstants.HTTP_CONNECTOR_MODE; import static com.google.apphosting.runtime.AppEngineConstants.IGNORE_RESPONSE_SIZE_LIMIT; import static java.nio.charset.StandardCharsets.UTF_8; @@ -63,7 +64,7 @@ public class JettyServletEngineAdapter implements ServletEngineAdapter { // java.util.logging) instead of writing to System.err // Documentation: http://www.eclipse.org/jetty/documentation/current/configuring-logging.html System.setProperty("org.eclipse.jetty.util.log.class", JettyLogger.class.getName()); - if (Objects.equals(System.getenv("GAE_RUNTIME"), "java8")) { + if (Objects.equals(GAE_RUNTIME, "java8")) { // Remove internal URLs. System.setProperty("java.vendor.url", ""); System.setProperty("java.vendor.url.bug", ""); @@ -118,7 +119,7 @@ public void start(String serverInfo, ServletEngineAdapter.Config runtimeOptions) server.setHandler(appVersionHandlerMap); boolean ignoreResponseSizeLimit = - Objects.equals(System.getenv("GAE_RUNTIME"), "java8") + Objects.equals(GAE_RUNTIME, "java8") || Boolean.getBoolean(IGNORE_RESPONSE_SIZE_LIMIT); if (!ignoreResponseSizeLimit && !isHttpConnectorMode) { server.insertHandler(new SizeLimitHandler(-1, MAX_RESPONSE_SIZE)); diff --git a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnection.java b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnection.java index e69f7797d..acb273e5f 100644 --- a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnection.java +++ b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnection.java @@ -16,6 +16,9 @@ package com.google.apphosting.runtime.jetty9; +import static com.google.apphosting.runtime.AppEngineConstants.GAE_RUNTIME; +import static com.google.apphosting.runtime.AppEngineConstants.LEGACY_MODE; + import com.google.apphosting.base.AppVersionKey; import com.google.apphosting.base.protos.HttpPb.HttpRequest; import com.google.apphosting.base.protos.HttpPb.ParsedHttpHeader; @@ -70,7 +73,7 @@ public class RpcConnection implements Connection, HttpTransport { Boolean.parseBoolean( System.getProperty( "com.google.appengine.nomalize_inet_addr", - Boolean.toString(!"java8".equals(System.getenv("GAE_RUNTIME"))))); + Boolean.toString(!"java8".equals(GAE_RUNTIME)))); private final List listeners = new CopyOnWriteArrayList<>(); private final RpcConnector connector; @@ -180,7 +183,7 @@ public void onCompleted() { // pretend to parse the request line // LEGACY_MODE is case insensitive for known methods - HttpMethod method = RpcConnector.LEGACY_MODE + HttpMethod method = LEGACY_MODE ? HttpMethod.INSENSITIVE_CACHE.get(rpc.getProtocol()) : HttpMethod.CACHE.get(rpc.getProtocol()); String methodS = method != null ? method.asString() : rpc.getProtocol(); @@ -201,7 +204,7 @@ public void onCompleted() { HttpField field = getField(header); // Handle LegacyMode Headers - if (RpcConnector.LEGACY_MODE && field.getHeader() != null) { + if (LEGACY_MODE && field.getHeader() != null) { switch (field.getHeader()) { case CONTENT_ENCODING: continue; @@ -281,7 +284,7 @@ public void onCompleted() { // enable it only for non java8 runtimes. if ((exception == null) && (abortedError != null) - && !"java8".equals(System.getenv("GAE_RUNTIME"))) { + && !"java8".equals(GAE_RUNTIME)) { exception = abortedError; } diff --git a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnector.java b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnector.java index be32d4e08..6efcab5e5 100644 --- a/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnector.java +++ b/runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/RpcConnector.java @@ -16,10 +16,11 @@ package com.google.apphosting.runtime.jetty9; +import static com.google.apphosting.runtime.AppEngineConstants.LEGACY_MODE; + import com.google.apphosting.base.AppVersionKey; import com.google.apphosting.base.protos.RuntimePb.UPRequest; import com.google.apphosting.runtime.MutableUpResponse; -import com.google.apphosting.runtime.jetty9.RpcEndPoint; import java.io.IOException; import javax.servlet.ServletException; import org.eclipse.jetty.http.CookieCompliance; @@ -50,14 +51,6 @@ public class RpcConnector extends AbstractConnector { private final HttpConfiguration httpConfiguration = new HttpConfiguration(); - /** - * If Legacy Mode is tunred on, then Jetty is configured to be more forgiving of bad requests - * and to act more in the style of Jetty-9.3 - */ - // Keep this public property name, do not change to jetty9 as it is public contract. - static final boolean LEGACY_MODE = - Boolean.getBoolean("com.google.apphosting.runtime.jetty94.LEGACY_MODE"); // Keep 94 name. - public RpcConnector(Server server) { super(server, null, null, null, 0, new RpcConnectionFactory());