This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch support/nifi-1.x
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/support/nifi-1.x by this push:
new b3fb0b2713 NIFI-12516 Corrected Cluster Replicated Response Headers
for HTTP/2
b3fb0b2713 is described below
commit b3fb0b2713d3e6f1c7ae6578b71d9e31a2aca195
Author: Mark Payne <[email protected]>
AuthorDate: Fri Dec 15 12:12:48 2023 -0500
NIFI-12516 Corrected Cluster Replicated Response Headers for HTTP/2
The headers in the map that come back when replicating a request used to be
in the case given; however they can be lowercased in the OkHttp Headers object
when using HTTP/2 instead of HTTP/1.1. As a result, we need to ensure that we
always use lower-case header names or check the map case-insensitive.
This closes #8163
Signed-off-by: David Handermann <[email protected]>
(cherry picked from commit 231dbde4b30bfea5b711169fe6f125c9279ec450)
---
.../http/replication/okhttp/JacksonResponse.java | 9 ++++--
.../apache/nifi/web/StandardNiFiContentAccess.java | 36 ++++++++++++++++++++--
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/replication/okhttp/JacksonResponse.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/replication/okhttp/JacksonResponse.java
index e4eb45cf1f..3f10d42f89 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/replication/okhttp/JacksonResponse.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/replication/okhttp/JacksonResponse.java
@@ -231,7 +231,12 @@ public class JacksonResponse extends Response {
}
@Override
- public String getHeaderString(String name) {
- return responseHeaders.getFirst(name);
+ public String getHeaderString(final String name) {
+ final String headerValue = responseHeaders.getFirst(name);
+ if (headerValue != null) {
+ return headerValue;
+ }
+
+ return responseHeaders.getFirst(name.toLowerCase());
}
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
index 79973fe147..7271b7ffaa 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
@@ -35,6 +35,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
@@ -113,11 +114,11 @@ public class StandardNiFiContentAccess implements
ContentAccess {
}
// get the file name
- final String contentDisposition =
responseHeaders.getFirst("Content-Disposition");
+ final String contentDisposition = getHeader(responseHeaders,
"content-disposition");
final String filename =
StringUtils.substringBetween(contentDisposition, "filename=\"", "\"");
// get the content type
- final String contentType =
responseHeaders.getFirst("Content-Type");
+ final String contentType = getHeader(responseHeaders,
"content-type");
// create the downloadable content
return new DownloadableContent(filename, contentType,
nodeResponse.getInputStream());
@@ -159,6 +160,37 @@ public class StandardNiFiContentAccess implements
ContentAccess {
}
}
+ /**
+ * Returns the value of the first header in the given header map whose
name matches the given header name.
+ * In HTTP 2.0, all header names should be lower-case. Before that, they
were not necessarily. The spec, however,
+ * indicates that header names are case-insensitive. That said, the code
has them stored in a Map, and the keys in Maps
+ * are not case-insensitive. This method allows us to access the value of
the first header with the given name,
+ * ignoring case.
+ *
+ * @param headers the map containing all headers
+ * @param headerName the case-insensitive name of the header to retrieve
+ * @return the value of the first header with the given name, or
<code>null</code> if the header is not found
+ */
+ private String getHeader(final MultivaluedMap<String, String> headers,
final String headerName) {
+ if (headers == null || headers.isEmpty() || headerName == null ||
headerName.isBlank()) {
+ return null;
+ }
+
+ final String exactMatch = headers.getFirst(headerName);
+ if (exactMatch != null) {
+ return exactMatch;
+ }
+
+ for (final Map.Entry<String, List<String>> entry : headers.entrySet())
{
+ if (entry.getKey().equalsIgnoreCase(headerName)) {
+ final List<String> values = entry.getValue();
+ return values == null || values.isEmpty() ? null :
values.get(0);
+ }
+ }
+
+ return null;
+ }
+
private DownloadableContent getFlowFileContent(final String connectionId,
final String flowfileId, final String dataUri) {
// user authorization is handled once we have the actual content so we
can utilize the flow file attributes in the resource context
return serviceFacade.getContent(connectionId, flowfileId, dataUri);