This is an automated email from the ASF dual-hosted git repository. pvillard pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push: new 6841aa6e99 NIFI-12047 Added HTTP/2 to Default Application Protocols 6841aa6e99 is described below commit 6841aa6e99ab794a61164712e0936914b4e96f79 Author: exceptionfactory <exceptionfact...@apache.org> AuthorDate: Mon Sep 11 16:57:13 2023 -0500 NIFI-12047 Added HTTP/2 to Default Application Protocols - Changed default value of nifi.web.https.application.protocols to include both h2 and http/1.1 - Changed default value of nifi.registry.web.https.application.protocols to include both h2 and http/1.1 - Updated HostHeaderHandler logging Signed-off-by: Pierre Villard <pierre.villard...@gmail.com> This closes #7684. --- .../java/org/apache/nifi/util/NiFiProperties.java | 4 +- .../nifi-framework/nifi-resources/pom.xml | 2 +- .../apache/nifi/web/server/HostHeaderHandler.java | 81 ++++++---------------- .../connector/FrameworkServerConnectorFactory.java | 4 ++ .../nifi/web/server/HostHeaderHandlerTest.java | 22 ------ .../FrameworkServerConnectorFactoryTest.java | 5 +- nifi-registry/nifi-registry-assembly/pom.xml | 2 +- .../properties/NiFiRegistryProperties.java | 4 +- 8 files changed, 32 insertions(+), 92 deletions(-) diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java index 92cfde96d1..9c4763b0b6 100644 --- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java @@ -350,7 +350,7 @@ public class NiFiProperties extends ApplicationProperties { public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml"; public static final String DEFAULT_LOGIN_IDENTITY_PROVIDER_CONFIGURATION_FILE = "conf/login-identity-providers.xml"; public static final Integer DEFAULT_REMOTE_INPUT_PORT = null; - private static final String DEFAULT_WEB_HTTPS_APPLICATION_PROTOCOLS = "http/1.1"; + private static final String DEFAULT_WEB_HTTPS_APPLICATION_PROTOCOLS = "h2 http/1.1"; public static final int DEFAULT_WEB_THREADS = 200; public static final String DEFAULT_WEB_MAX_HEADER_SIZE = "16 KB"; public static final String DEFAULT_WEB_WORKING_DIR = "./work/jetty"; @@ -725,7 +725,7 @@ public class NiFiProperties extends ApplicationProperties { } /** - * Get Web HTTPS Application Protocols defaults to HTTP/1.1 + * Get Web HTTPS Application Protocols defaults to HTTP/2 and HTTP/1.1 * * @return Set of configured HTTPS Application Protocols */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml index 723f2eee4a..5c430f5aef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml @@ -127,7 +127,7 @@ <nifi.web.https.host>127.0.0.1</nifi.web.https.host> <nifi.web.https.port>8443</nifi.web.https.port> <nifi.web.https.network.interface.default /> - <nifi.web.https.application.protocols>http/1.1</nifi.web.https.application.protocols> + <nifi.web.https.application.protocols>h2 http/1.1</nifi.web.https.application.protocols> <nifi.jetty.work.dir>./work/jetty</nifi.jetty.work.dir> <nifi.web.jetty.threads>200</nifi.web.jetty.threads> <nifi.web.max.header.size>16 KB</nifi.web.max.header.size> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/HostHeaderHandler.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/HostHeaderHandler.java index 5cc917ff52..62348bb53b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/HostHeaderHandler.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/HostHeaderHandler.java @@ -47,52 +47,13 @@ public class HostHeaderHandler extends ScopedHandler { private final int serverPort; private final List<String> validHosts; - /** - * Instantiates a handler with a given server name and port 0. - * - * @param serverName the {@code serverName} to set on the request (the {@code serverPort} will not be set) - * @deprecated Use {@link #HostHeaderHandler(NiFiProperties)} which accepts a {@link NiFiProperties} object to allow for custom network interface binding. - */ - public HostHeaderHandler(String serverName) { - this(serverName, 0); - } - - /** - * Instantiates a handler with a given server name and port. - * - * @param serverName the {@code serverName} to set on the request - * @param serverPort the {@code serverPort} to set on the request - * @deprecated Use {@link #HostHeaderHandler(NiFiProperties)} which accepts a {@link NiFiProperties} object to allow for custom network interface binding. - */ - public HostHeaderHandler(String serverName, int serverPort) { - this.serverName = Objects.requireNonNull(serverName); - this.serverPort = serverPort; - - validHosts = generateDefaultHostnames(null); - validHosts.add(serverName.toLowerCase()); - validHosts.add(serverName.toLowerCase() + ":" + serverPort); - // Sometimes the hostname is left empty but the port is always populated - validHosts.add("localhost"); - validHosts.add("localhost:" + serverPort); - // Different from customizer -- empty is ok here - validHosts.add(""); - try { - validHosts.add(InetAddress.getLocalHost().getHostName().toLowerCase()); - validHosts.add(InetAddress.getLocalHost().getHostName().toLowerCase() + ":" + serverPort); - } catch (final Exception e) { - logger.warn("Failed to determine local hostname.", e); - } - - logger.info("Created " + this.toString()); - } - /** * Instantiates a handler which accepts incoming requests with a host header that is empty or contains one of the * valid hosts. See the Apache NiFi Admin Guide for instructions on how to set valid hostnames and IP addresses. * * @param niFiProperties the NiFiProperties */ - public HostHeaderHandler(NiFiProperties niFiProperties) { + public HostHeaderHandler(final NiFiProperties niFiProperties) { this.serverName = Objects.requireNonNull(determineServerHostname(niFiProperties)); this.serverPort = determineServerPort(niFiProperties); @@ -110,9 +71,7 @@ public class HostHeaderHandler extends ScopedHandler { hosts.add(""); this.validHosts = uniqueList(hosts); - logger.info("Determined {} valid hostnames and IP addresses for incoming headers: {}", new Object[]{validHosts.size(), StringUtils.join(validHosts, ", ")}); - - logger.debug("Created " + this.toString()); + logger.info("{} valid values for HTTP Request Host Header: {}", validHosts.size(), StringUtils.join(validHosts, ", ")); } /** @@ -145,7 +104,7 @@ public class HostHeaderHandler extends ScopedHandler { customHostnames.addAll(portlessHostnames); if (logger.isDebugEnabled()) { - logger.debug("Parsed {} custom hostnames from nifi.web.proxy.host: {}", new Object[]{customHostnames.size(), StringUtils.join(customHostnames, ", ")}); + logger.debug("Parsed {} custom hostnames from nifi.web.proxy.host: {}", customHostnames.size(), StringUtils.join(customHostnames, ", ")); } return uniqueList(customHostnames); } @@ -164,7 +123,6 @@ public class HostHeaderHandler extends ScopedHandler { * Returns true if the provided address is an IPv6 address (or could be interpreted as one). This method is more * lenient than {@link InetAddressUtils#isIPv6Address(String)} because of different interpretations of IPv4-mapped * IPv6 addresses. - * * See RFC 5952 Section 4 for more information on textual representation of the IPv6 addresses. * * @param address the address in text form @@ -178,8 +136,6 @@ public class HostHeaderHandler extends ScopedHandler { // If the last two hextets are written in IPv4 form, treat it as an IPv6 address as well String everythingAfterLastColon = StringUtils.substringAfterLast(address, ":"); boolean isIPv4 = InetAddressUtils.isIPv4Address(everythingAfterLastColon); - boolean isIPv4Mapped = InetAddressUtils.isIPv4MappedIPv64Address(everythingAfterLastColon); - boolean isCompressable = address.contains("0:0") && !address.contains("::"); return isNormalIPv6 || isIPv4; } @@ -197,14 +153,18 @@ public class HostHeaderHandler extends ScopedHandler { } @Override - public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - logger.debug("HostHeaderHandler#doScope on " + request.getRequestURI()); + public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { nextScope(target, baseRequest, request, response); } - boolean hostHeaderIsValid(String hostHeader) { - return validHosts.contains(hostHeader.toLowerCase().trim()); + /** + * Host Header Valid status checks against valid hosts + * + * @param hostHeader Host header value + * @return Valid status + */ + boolean hostHeaderIsValid(final String hostHeader) { + return hostHeader != null && validHosts.contains(hostHeader.toLowerCase().trim()); } @Override @@ -222,21 +182,20 @@ public class HostHeaderHandler extends ScopedHandler { * @param response the current response */ @Override - public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { final String hostHeader = request.getHeader("Host"); - logger.debug("Received request [" + request.getRequestURI() + "] with host header: " + hostHeader); + final String requestUri = request.getRequestURI(); + logger.debug("Request URI [{}] Host Header [{}]", requestUri, hostHeader); + if (!hostHeaderIsValid(hostHeader)) { - logger.warn("Request host header [" + hostHeader + "] different from web hostname [" + - serverName + "(:" + serverPort + ")]. Overriding to [" + serverName + ":" + - serverPort + request.getRequestURI() + "]"); + logger.warn("Request URI [{}] Host Header [{}] not valid", requestUri, hostHeader); response.setContentType("text/html; charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); - PrintWriter out = response.getWriter(); + final PrintWriter out = response.getWriter(); out.println("<h1>System Error</h1>"); - // TODO: Change to org.apache.commons.text.StringEscapeUtils out.println("<h2>The request contained an invalid host header [<code>" + StringEscapeUtils.escapeHtml4(hostHeader) + "</code>] in the request [<code>" + StringEscapeUtils.escapeHtml4(request.getRequestURI()) + "</code>]. Check for request manipulation or third-party intercept.</h2>"); @@ -308,7 +267,7 @@ public class HostHeaderHandler extends ScopedHandler { // Dedupe but maintain order final List<String> uniqueHosts = uniqueList(validHosts); if (logger.isDebugEnabled()) { - logger.debug("Determined {} valid default hostnames and IP addresses for incoming headers: {}", new Object[]{uniqueHosts.size(), StringUtils.join(uniqueHosts, ", ")}); + logger.debug("Determined {} valid default hostnames and IP addresses for incoming headers: {}", uniqueHosts.size(), StringUtils.join(uniqueHosts, ", ")); } return uniqueHosts; } @@ -333,7 +292,7 @@ public class HostHeaderHandler extends ScopedHandler { try { NetworkInterface ni = NetworkInterface.getByName(networkInterfaceName); List<String> ipAddresses = Collections.list(ni.getInetAddresses()).stream().map(inetAddress -> inetAddress.getHostAddress().toLowerCase()).collect(Collectors.toList()); - logger.debug("Resolved the following IP addresses for network interface {}: {}", new Object[]{networkInterfaceName, StringUtils.join(ipAddresses, ", ")}); + logger.debug("Resolved the following IP addresses for network interface {}: {}", networkInterfaceName, StringUtils.join(ipAddresses, ", ")); allIPAddresses.addAll(ipAddresses); } catch (SocketException e) { logger.warn("Cannot resolve network interface named " + networkInterfaceName); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java index 829a5578f6..78766780f1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java @@ -28,6 +28,7 @@ import org.apache.nifi.security.util.TlsPlatform; import org.apache.nifi.util.FormatUtils; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.web.server.util.StoreScanner; +import org.eclipse.jetty.server.HostHeaderCustomizer; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -124,6 +125,9 @@ public class FrameworkServerConnectorFactory extends StandardServerConnectorFact httpConfiguration.setResponseHeaderSize(headerSize); httpConfiguration.setIdleTimeout(idleTimeout); + // Add HostHeaderCustomizer to set Host Header for HTTP/2 and HostHeaderHandler + httpConfiguration.addCustomizer(new HostHeaderCustomizer()); + return httpConfiguration; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java index 579ad4c2e3..417fd70135 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java @@ -49,14 +49,12 @@ public class HostHeaderHandlerTest { "FFFF:129.144.52.38", "::FFFF:129.144.52.38"); - private static List<String> defaultHostsAndPorts150; private static List<String> defaultHostsAndPorts; @BeforeAll public static void setUpOnce() throws Exception { String actualHostname = InetAddress.getLocalHost().getHostName().toLowerCase(); List<String> defaultHosts150 = Arrays.asList(DEFAULT_HOSTNAME, "localhost", actualHostname); - defaultHostsAndPorts150 = buildHostsWithPorts(defaultHosts150, DEFAULT_PORT); String actualIp = InetAddress.getLocalHost().getHostAddress(); String loopbackIp = InetAddress.getLoopbackAddress().getHostAddress(); List<String> defaultHosts = new ArrayList<>(defaultHosts150); @@ -65,26 +63,6 @@ public class HostHeaderHandlerTest { defaultHostsAndPorts = buildHostsWithPorts(defaultHosts, DEFAULT_PORT); } - @SuppressWarnings("deprecation") - @Test - public void testConstructorShouldAcceptSingleValues() { - HostHeaderHandler handler = new HostHeaderHandler(DEFAULT_HOSTNAME, DEFAULT_PORT); - - assertTrue(handler.hostHeaderIsValid(DEFAULT_HOSTNAME)); - assertTrue(handler.hostHeaderIsValid(DEFAULT_HOSTNAME + ":" + DEFAULT_PORT)); - } - - /** - * The feature was introduced in Apache NiFi 1.5.0 but the behavior was changed following that release to include the actual IP address of the server, IPv6 ::1, and 127.0.0.1. - */ - @SuppressWarnings("deprecation") - @Test - public void testShouldHandle_1_5_0_DefaultValues() { - HostHeaderHandler handler = new HostHeaderHandler(DEFAULT_HOSTNAME, DEFAULT_PORT); - - defaultHostsAndPorts150.forEach(host -> assertTrue(handler.hostHeaderIsValid(host))); - } - @Test public void testNewConstructorShouldHandleCurrentDefaultValues() { HostHeaderHandler handler = new HostHeaderHandler(getNifiProperties(null)); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java index f4119f76aa..17e5858763 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java @@ -36,7 +36,6 @@ import java.util.Properties; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -110,7 +109,7 @@ class FrameworkServerConnectorFactoryTest { assertHttpConnectionFactoryFound(serverConnector); final SslConnectionFactory sslConnectionFactory = assertSslConnectionFactoryFound(serverConnector); - final SslContextFactory.Server sslContextFactory = (SslContextFactory.Server) sslConnectionFactory.getSslContextFactory(); + final SslContextFactory.Server sslContextFactory = sslConnectionFactory.getSslContextFactory(); assertTrue(sslContextFactory.getNeedClientAuth()); assertFalse(sslContextFactory.getWantClientAuth()); @@ -118,7 +117,7 @@ class FrameworkServerConnectorFactoryTest { assertAutoReloadEnabled(serverConnector); final HTTP2ServerConnectionFactory http2ServerConnectionFactory = serverConnector.getConnectionFactory(HTTP2ServerConnectionFactory.class); - assertNull(http2ServerConnectionFactory); + assertNotNull(http2ServerConnectionFactory); } @Test diff --git a/nifi-registry/nifi-registry-assembly/pom.xml b/nifi-registry/nifi-registry-assembly/pom.xml index f382f8db6b..dd3d009b8d 100644 --- a/nifi-registry/nifi-registry-assembly/pom.xml +++ b/nifi-registry/nifi-registry-assembly/pom.xml @@ -164,7 +164,7 @@ <nifi.registry.web.https.host /> <nifi.registry.web.https.port /> <nifi.registry.web.https.network.interface.default /> - <nifi.registry.web.https.application.protocols>http/1.1</nifi.registry.web.https.application.protocols> + <nifi.registry.web.https.application.protocols>h2 http/1.1</nifi.registry.web.https.application.protocols> <nifi.registry.jetty.work.dir>./work/jetty</nifi.registry.jetty.work.dir> <nifi.registry.web.jetty.threads>200</nifi.registry.web.jetty.threads> <nifi.registry.web.should.send.server.version>true</nifi.registry.web.should.send.server.version> diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java index d72acd058b..12df974c13 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java @@ -123,7 +123,7 @@ public class NiFiRegistryProperties extends ApplicationProperties { // Defaults public static final String DEFAULT_WEB_WORKING_DIR = "./work/jetty"; - public static final String DEFAULT_WEB_HTTPS_APPLICATION_PROTOCOLS = "http/1.1"; + public static final String DEFAULT_WEB_HTTPS_APPLICATION_PROTOCOLS = "h2 http/1.1"; public static final String DEFAULT_WAR_DIR = "./lib"; public static final String DEFAULT_PROVIDERS_CONFIGURATION_FILE = "./conf/providers.xml"; public static final String DEFAULT_REGISTRY_ALIAS_CONFIGURATION_FILE = "./conf/registry-aliases.xml"; @@ -235,7 +235,7 @@ public class NiFiRegistryProperties extends ApplicationProperties { } /** - * Get Web HTTPS Application Protocols defaults to HTTP/1.1 + * Get Web HTTPS Application Protocols defaults to HTTP/2 and HTTP/1.1 * * @return Set of configured HTTPS Application Protocols */