forked from apache/nifi
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NIFI-13594 Added web-servlet-shared abstracted from web-utils (apache…
…#9123) - Moved RequestUriBuilder from web-utils to web-servlet-shared - Refactored proxy header parsing from WebUtils to StandardRequestUriProvider - Renamed WebUtils to WebClientUtils This closes apache#9123
- Loading branch information
1 parent
f262e74
commit 33da346
Showing
43 changed files
with
895 additions
and
782 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
Licensed to the Apache Software Foundation (ASF) under one or more | ||
contributor license agreements. See the NOTICE file distributed with | ||
this work for additional information regarding copyright ownership. | ||
The ASF licenses this file to You under the Apache License, Version 2.0 | ||
(the "License"); you may not use this file except in compliance with | ||
the License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.apache.nifi</groupId> | ||
<artifactId>nifi-commons</artifactId> | ||
<version>2.0.0-SNAPSHOT</version> | ||
</parent> | ||
<artifactId>nifi-web-servlet-shared</artifactId> | ||
<description>Shared classes for handling HTTP Servlet requests and responses</description> | ||
<dependencies> | ||
<dependency> | ||
<groupId>jakarta.servlet</groupId> | ||
<artifactId>jakarta.servlet-api</artifactId> | ||
<version>${servlet-api.version}</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
52 changes: 52 additions & 0 deletions
52
...nifi-web-servlet-shared/src/main/java/org/apache/nifi/web/servlet/shared/ProxyHeader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.nifi.web.servlet.shared; | ||
|
||
/** | ||
* Enumeration of supported Proxy Headers that provide information about the original request properties | ||
*/ | ||
public enum ProxyHeader { | ||
HOST("Host"), | ||
|
||
PROXY_CONTEXT_PATH("X-ProxyContextPath"), | ||
|
||
PROXY_SCHEME("X-ProxyScheme"), | ||
|
||
PROXY_HOST("X-ProxyHost"), | ||
|
||
PROXY_PORT("X-ProxyPort"), | ||
|
||
FORWARDED_CONTEXT("X-Forwarded-Context"), | ||
|
||
FORWARDED_PREFIX("X-Forwarded-Prefix"), | ||
|
||
FORWARDED_PROTO("X-Forwarded-Proto"), | ||
|
||
FORWARDED_HOST("X-Forwarded-Host"), | ||
|
||
FORWARDED_PORT("X-Forwarded-Port"); | ||
|
||
private final String header; | ||
|
||
ProxyHeader(final String header) { | ||
this.header = header; | ||
} | ||
|
||
public String getHeader() { | ||
return header; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
...b-servlet-shared/src/main/java/org/apache/nifi/web/servlet/shared/RequestUriProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.nifi.web.servlet.shared; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
|
||
import java.net.URI; | ||
|
||
/** | ||
* Abstraction for resolving and returning an HTTP Request URI based on presented headers and configured properties | ||
*/ | ||
public interface RequestUriProvider { | ||
/** | ||
* Get Request URI from HTTP Servlet Request containing optional headers | ||
* | ||
* @param request HTTP Servlet Request | ||
* @return Request URI | ||
*/ | ||
URI getRequestUri(HttpServletRequest request); | ||
} |
195 changes: 195 additions & 0 deletions
195
...t-shared/src/main/java/org/apache/nifi/web/servlet/shared/StandardRequestUriProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.nifi.web.servlet.shared; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
|
||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.function.Predicate; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* Standard implementation of Request URI Provider with allowed hosts and context paths | ||
*/ | ||
public class StandardRequestUriProvider implements RequestUriProvider { | ||
private static final Pattern HOST_PATTERN = Pattern.compile("^([^:]+):?([1-9][0-9]{2,4})?$"); | ||
|
||
private static final Pattern HOST_PORT_REQUIRED_PATTERN = Pattern.compile("^[^:]+:([1-9][0-9]{2,4})$"); | ||
|
||
private static final Pattern SCHEME_PATTERN = Pattern.compile("^https?$"); | ||
|
||
private static final int FIRST_GROUP = 1; | ||
|
||
private static final int MINIMUM_PORT_NUMBER = 100; | ||
|
||
private static final int MAXIMUM_PORT_NUMBER = 65535; | ||
|
||
private static final String EMPTY_PATH = ""; | ||
|
||
private static final String ROOT_PATH = "/"; | ||
|
||
private final List<String> allowedContextPaths; | ||
|
||
public StandardRequestUriProvider(final List<String> allowedContextPaths) { | ||
this.allowedContextPaths = Objects.requireNonNull(allowedContextPaths); | ||
} | ||
|
||
/** | ||
* Get Request URI from HTTP Servlet Request containing optional headers and validated against allowed context paths | ||
* | ||
* @param request HTTP Servlet Request | ||
* @return Request URI | ||
*/ | ||
@Override | ||
public URI getRequestUri(final HttpServletRequest request) { | ||
Objects.requireNonNull(request, "HTTP Servlet Request required"); | ||
|
||
final String scheme = getScheme(request); | ||
final String host = getHost(request); | ||
final int port = getPort(request); | ||
final String path = getPath(request); | ||
|
||
try { | ||
return new URI(scheme, null, host, port, path, null, null); | ||
} catch (final URISyntaxException e) { | ||
throw new IllegalArgumentException("Request URI construction failed", e); | ||
} | ||
} | ||
|
||
private String getScheme(final HttpServletRequest request) { | ||
final String scheme; | ||
|
||
final String requestScheme = request.getScheme(); | ||
final String headerScheme = getFirstHeader(request, ProxyHeader.PROXY_SCHEME, ProxyHeader.FORWARDED_PROTO); | ||
if (headerScheme == null) { | ||
scheme = requestScheme; | ||
} else { | ||
final Matcher matcher = SCHEME_PATTERN.matcher(headerScheme); | ||
if (matcher.matches()) { | ||
scheme = headerScheme; | ||
} else { | ||
scheme = requestScheme; | ||
} | ||
} | ||
|
||
return scheme; | ||
} | ||
|
||
private String getHost(final HttpServletRequest request) { | ||
final String host; | ||
|
||
final String serverName = request.getServerName(); | ||
final String headerHost = getFirstHeader(request, ProxyHeader.PROXY_HOST, ProxyHeader.FORWARDED_HOST, ProxyHeader.HOST); | ||
if (headerHost == null) { | ||
host = serverName; | ||
} else { | ||
final Matcher matcher = HOST_PATTERN.matcher(headerHost); | ||
if (matcher.matches()) { | ||
host = matcher.group(FIRST_GROUP); | ||
} else { | ||
host = serverName; | ||
} | ||
} | ||
|
||
return host; | ||
} | ||
|
||
private int getPort(final HttpServletRequest request) { | ||
final int port; | ||
|
||
final int serverPort = request.getServerPort(); | ||
final String headerHost = getFirstHeader(request, ProxyHeader.PROXY_HOST, ProxyHeader.FORWARDED_HOST); | ||
if (headerHost == null) { | ||
port = getProxyPort(request); | ||
} else { | ||
final Matcher matcher = HOST_PORT_REQUIRED_PATTERN.matcher(headerHost); | ||
if (matcher.matches()) { | ||
final String headerPort = matcher.group(FIRST_GROUP); | ||
port = getParsedPort(headerPort, serverPort); | ||
} else { | ||
port = getProxyPort(request); | ||
} | ||
} | ||
|
||
return port; | ||
} | ||
|
||
private int getProxyPort(final HttpServletRequest request) { | ||
final int port; | ||
|
||
final int serverPort = request.getServerPort(); | ||
final String headerPort = getFirstHeader(request, ProxyHeader.PROXY_PORT, ProxyHeader.FORWARDED_PORT); | ||
if (headerPort == null) { | ||
port = serverPort; | ||
} else { | ||
port = getParsedPort(headerPort, serverPort); | ||
} | ||
|
||
return port; | ||
} | ||
|
||
private int getParsedPort(final String headerPort, final int serverPort) { | ||
int port; | ||
|
||
try { | ||
final int parsedPort = Integer.parseInt(headerPort); | ||
if (parsedPort < MINIMUM_PORT_NUMBER || parsedPort > MAXIMUM_PORT_NUMBER) { | ||
port = serverPort; | ||
} else { | ||
port = parsedPort; | ||
} | ||
} catch (final Exception e) { | ||
port = serverPort; | ||
} | ||
|
||
return port; | ||
} | ||
|
||
private String getPath(final HttpServletRequest request) { | ||
final String path; | ||
|
||
final String headerPath = getFirstHeader(request, ProxyHeader.PROXY_CONTEXT_PATH, ProxyHeader.FORWARDED_CONTEXT, ProxyHeader.FORWARDED_PREFIX); | ||
if (headerPath == null) { | ||
path = EMPTY_PATH; | ||
} else if (ROOT_PATH.equals(headerPath)) { | ||
path = ROOT_PATH; | ||
} else { | ||
if (allowedContextPaths.contains(headerPath)) { | ||
path = headerPath; | ||
} else { | ||
throw new IllegalArgumentException("Request Header Context Path not allowed based on properties [nifi.web.proxy.context.path]"); | ||
} | ||
} | ||
|
||
return path; | ||
} | ||
|
||
private String getFirstHeader(final HttpServletRequest request, final ProxyHeader... proxyHeaders) { | ||
return Arrays.stream(proxyHeaders) | ||
.map(ProxyHeader::getHeader) | ||
.map(request::getHeader) | ||
.filter(Objects::nonNull) | ||
.filter(Predicate.not(String::isBlank)) | ||
.findFirst() | ||
.orElse(null); | ||
} | ||
} |
Oops, something went wrong.