Skip to content

Commit 2b1cc51

Browse files
NIFI-15214 Refactored site-to-site-client using Java HttpClient
- Refactored ClusterLoadBalanceAuthorizer wildcard certificate verification - Removed Apache HttpClient 4 from framework modules
1 parent 730bf0f commit 2b1cc51

File tree

14 files changed

+1076
-1093
lines changed

14 files changed

+1076
-1093
lines changed

nifi-commons/nifi-site-to-site-client/pom.xml

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
2424

2525
<artifactId>nifi-site-to-site-client</artifactId>
2626

27-
<properties>
28-
<httpclient.version>${org.apache.httpcomponents.httpclient.version}</httpclient.version>
29-
</properties>
30-
3127
<dependencies>
3228
<dependency>
3329
<groupId>org.apache.nifi</groupId>
@@ -71,53 +67,22 @@
7167
<version>2.7.0-SNAPSHOT</version>
7268
</dependency>
7369
<dependency>
74-
<groupId>org.apache.httpcomponents</groupId>
75-
<artifactId>httpclient</artifactId>
76-
<exclusions>
77-
<exclusion>
78-
<groupId>commons-logging</groupId>
79-
<artifactId>commons-logging</artifactId>
80-
</exclusion>
81-
</exclusions>
82-
</dependency>
83-
<dependency>
84-
<groupId>org.apache.httpcomponents</groupId>
85-
<artifactId>httpcore-nio</artifactId>
86-
<exclusions>
87-
<exclusion>
88-
<groupId>commons-logging</groupId>
89-
<artifactId>commons-logging</artifactId>
90-
</exclusion>
91-
</exclusions>
92-
</dependency>
93-
<dependency>
94-
<groupId>org.apache.httpcomponents</groupId>
95-
<artifactId>httpcore</artifactId>
96-
<exclusions>
97-
<exclusion>
98-
<groupId>commons-logging</groupId>
99-
<artifactId>commons-logging</artifactId>
100-
</exclusion>
101-
</exclusions>
70+
<groupId>jakarta.xml.bind</groupId>
71+
<artifactId>jakarta.xml.bind-api</artifactId>
10272
</dependency>
10373
<dependency>
104-
<groupId>org.apache.httpcomponents</groupId>
105-
<artifactId>httpasyncclient</artifactId>
106-
<version>4.1.5</version>
107-
<exclusions>
108-
<exclusion>
109-
<groupId>commons-logging</groupId>
110-
<artifactId>commons-logging</artifactId>
111-
</exclusion>
112-
</exclusions>
74+
<groupId>org.slf4j</groupId>
75+
<artifactId>slf4j-api</artifactId>
11376
</dependency>
11477
<dependency>
11578
<groupId>org.slf4j</groupId>
116-
<artifactId>slf4j-api</artifactId>
79+
<artifactId>jcl-over-slf4j</artifactId>
80+
<scope>test</scope>
11781
</dependency>
11882
<dependency>
119-
<groupId>jakarta.xml.bind</groupId>
120-
<artifactId>jakarta.xml.bind-api</artifactId>
83+
<groupId>com.squareup.okhttp3</groupId>
84+
<artifactId>mockwebserver3</artifactId>
85+
<scope>test</scope>
12186
</dependency>
12287
</dependencies>
12388
</project>

nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/protocol/http/HttpProxy.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
*/
1717
package org.apache.nifi.remote.protocol.http;
1818

19-
import org.apache.commons.lang3.StringUtils;
20-
import org.apache.http.HttpHost;
21-
2219
public class HttpProxy {
2320
private final String host;
2421
private final Integer port;
@@ -32,7 +29,6 @@ public HttpProxy(final String host, final Integer port, final String username, f
3229
this.password = password;
3330
}
3431

35-
3632
public String getHost() {
3733
return host;
3834
}
@@ -48,12 +44,4 @@ public String getUsername() {
4844
public String getPassword() {
4945
return password;
5046
}
51-
52-
public HttpHost getHttpHost() {
53-
if (StringUtils.isEmpty(host)) {
54-
return null;
55-
}
56-
return new HttpHost(host, port == null ? 80 : port);
57-
}
58-
5947
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.nifi.remote.util;
18+
19+
import org.apache.commons.lang3.StringUtils;
20+
21+
import java.net.URI;
22+
import java.net.URISyntaxException;
23+
import java.util.Arrays;
24+
import java.util.Collections;
25+
import java.util.LinkedHashSet;
26+
import java.util.Objects;
27+
import java.util.Set;
28+
import java.util.function.Predicate;
29+
30+
/**
31+
* Site-To-Site Cluster URL Parser
32+
*/
33+
public class ClusterUrlParser {
34+
/**
35+
* Parse the comma-separated URLs string for the remote NiFi instances.
36+
*
37+
* @return A set containing one or more URLs
38+
* @throws IllegalArgumentException when it fails to parse the URLs string,
39+
* URLs string contains multiple protocols (http and https mix),
40+
* or none of URL is specified.
41+
*/
42+
public static Set<String> parseClusterUrls(final String clusterUrls) {
43+
final Set<String> urls = new LinkedHashSet<>();
44+
if (clusterUrls != null && !clusterUrls.isEmpty()) {
45+
Arrays.stream(clusterUrls.split(","))
46+
.map(String::trim)
47+
.filter(s -> !s.isEmpty())
48+
.forEach(s -> {
49+
validateUriString(s);
50+
urls.add(resolveBaseUrl(s).intern());
51+
});
52+
}
53+
54+
if (urls.isEmpty()) {
55+
throw new IllegalArgumentException("Cluster URL was not specified.");
56+
}
57+
58+
final Predicate<String> isHttps = url -> url.toLowerCase().startsWith("https:");
59+
if (urls.stream().anyMatch(isHttps) && urls.stream().anyMatch(isHttps.negate())) {
60+
throw new IllegalArgumentException("Different protocols are used in the cluster URLs " + clusterUrls);
61+
}
62+
63+
return Collections.unmodifiableSet(urls);
64+
}
65+
66+
static String resolveBaseUrl(final String clusterUrl) {
67+
Objects.requireNonNull(clusterUrl, "clusterUrl cannot be null.");
68+
final URI uri;
69+
try {
70+
uri = new URI(clusterUrl.trim());
71+
} catch (final URISyntaxException e) {
72+
throw new IllegalArgumentException("The specified URL is malformed: " + clusterUrl);
73+
}
74+
75+
return resolveBaseUrl(uri);
76+
}
77+
78+
private static void validateUriString(String s) {
79+
// parse the uri
80+
final URI uri;
81+
try {
82+
uri = URI.create(s);
83+
} catch (final IllegalArgumentException e) {
84+
throw new IllegalArgumentException("The specified remote process group URL is malformed: " + s);
85+
}
86+
87+
// validate each part of the uri
88+
if (uri.getScheme() == null || uri.getHost() == null) {
89+
throw new IllegalArgumentException("The specified remote process group URL is malformed: " + s);
90+
}
91+
92+
if (!(uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equalsIgnoreCase("https"))) {
93+
throw new IllegalArgumentException("The specified remote process group URL is invalid because it is not http or https: " + s);
94+
}
95+
}
96+
97+
/**
98+
* Resolve NiFi API url with leniency. This method does following conversion on uri path:
99+
* <ul>
100+
* <li>/ to /nifi-api</li>
101+
* <li>/nifi to /nifi-api</li>
102+
* <li>/some/path/ to /some/path/nifi-api</li>
103+
* </ul>
104+
* @param clusterUrl url to be resolved
105+
* @return resolved url
106+
*/
107+
private static String resolveBaseUrl(final URI clusterUrl) {
108+
109+
if (clusterUrl.getScheme() == null || clusterUrl.getHost() == null) {
110+
throw new IllegalArgumentException("The specified URL is malformed: " + clusterUrl);
111+
}
112+
113+
if (!(clusterUrl.getScheme().equalsIgnoreCase("http") || clusterUrl.getScheme().equalsIgnoreCase("https"))) {
114+
throw new IllegalArgumentException("The specified URL is invalid because it is not http or https: " + clusterUrl);
115+
}
116+
117+
118+
String uriPath = clusterUrl.getPath().trim();
119+
120+
if (StringUtils.isEmpty(uriPath) || uriPath.equals("/")) {
121+
uriPath = "/nifi";
122+
} else if (uriPath.endsWith("/")) {
123+
uriPath = uriPath.substring(0, uriPath.length() - 1);
124+
}
125+
126+
final StringBuilder uriPathBuilder = new StringBuilder(uriPath);
127+
if (uriPath.endsWith("/nifi")) {
128+
uriPathBuilder.append("-api");
129+
} else if (!uriPath.endsWith("/nifi-api")) {
130+
uriPathBuilder.append("/nifi-api");
131+
}
132+
133+
try {
134+
final URI uri = new URI(clusterUrl.getScheme(), null, clusterUrl.getHost(), clusterUrl.getPort(), uriPathBuilder.toString(), null, null);
135+
return uri.toString();
136+
} catch (URISyntaxException e) {
137+
throw new IllegalArgumentException(e);
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)