This is an automated email from the ASF dual-hosted git repository.

exceptionfactory 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 5c150ffd78 NIFI-12925 Updated ListenHTTP to return 405 for TRACE and 
OPTIONS
5c150ffd78 is described below

commit 5c150ffd786ec37be4821791654c8a65d4a49f6e
Author: Mark Bean <mark.o.b...@gmail.com>
AuthorDate: Fri Mar 22 13:57:55 2024 -0400

    NIFI-12925 Updated ListenHTTP to return 405 for TRACE and OPTIONS
    
    This closes #8548
    
    Signed-off-by: David Handermann <exceptionfact...@apache.org>d
---
 .../nifi/processors/standard/ListenHTTP.java       |  3 +-
 .../standard/servlets/ListenHTTPServlet.java       | 16 +++++++
 .../nifi/processors/standard/TestListenHTTP.java   | 52 +++++++++++++++-------
 3 files changed, 55 insertions(+), 16 deletions(-)

diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
index 6d8fd2485d..ef07b182f7 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
@@ -82,7 +82,8 @@ import java.util.regex.Pattern;
 @Tags({"ingest", "http", "https", "rest", "listen"})
 @CapabilityDescription("Starts an HTTP Server and listens on a given base path 
to transform incoming requests into FlowFiles. "
         + "The default URI of the Service will be 
http://{hostname}:{port}/contentListener. Only HEAD and POST requests are "
-        + "supported. GET, PUT, and DELETE will result in an error and the 
HTTP response status code 405. "
+        + "supported. GET, PUT, DELETE, OPTIONS and TRACE will result in an 
error and the HTTP response status code 405; "
+        + "CONNECT will also result in an error and the HTTP response status 
code 400. "
         + "GET is supported on <service_URI>/healthcheck. If the service is 
available, it returns \"200 OK\" with the content \"OK\". "
         + "The health check functionality can be configured to be accessible 
via a different port. "
         + "For details see the documentation of the \"Listening Port for 
health check requests\" property."
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/servlets/ListenHTTPServlet.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/servlets/ListenHTTPServlet.java
index 73f846e8d5..4a4bc49e32 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/servlets/ListenHTTPServlet.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/servlets/ListenHTTPServlet.java
@@ -157,6 +157,22 @@ public class ListenHTTPServlet extends HttpServlet {
         }
     }
 
+    private void notAllowed(final HttpServletRequest request, final 
HttpServletResponse response) throws IOException {
+        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method 
Not Allowed");
+    }
+
+    @Override
+    protected void doTrace(final HttpServletRequest request, final 
HttpServletResponse response) throws ServletException, IOException {
+        notAllowed(request, response);
+        logger.debug("Denying TRACE request; method not allowed.");
+    }
+
+    @Override
+    protected void doOptions(final HttpServletRequest request, final 
HttpServletResponse response) throws ServletException, IOException {
+        notAllowed(request, response);
+        logger.debug("Denying OPTIONS request; method not allowed.");
+    }
+
     @Override
     protected void doPost(final HttpServletRequest request, final 
HttpServletResponse response) throws ServletException, IOException {
 
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
index f0dbba3119..83c686edb5 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
@@ -103,8 +103,13 @@ public class TestListenHTTP {
 
     private static final int SOCKET_CONNECT_TIMEOUT = 100;
     private static final long SERVER_START_TIMEOUT = 1200000;
+
+    private static final String HTTP_POST = "POST";
+    private static final String HTTP_TRACE = "TRACE";
+    private static final String HTTP_OPTIONS = "OPTIONS";
+
     private static final Duration CLIENT_CALL_TIMEOUT = Duration.ofSeconds(10);
-    public static final String LOCALHOST_DN = "CN=localhost";
+    private static final String LOCALHOST_DN = "CN=localhost";
 
     private static TlsConfiguration serverConfiguration;
     private static TlsConfiguration serverTls_1_3_Configuration;
@@ -374,14 +379,14 @@ public class TestListenHTTP {
     public void 
testSecureServerTrustStoreConfiguredClientAuthenticationRequired() throws 
Exception {
         
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, 
serverConfiguration);
         final int port = startSecureServer();
-        assertThrows(IOException.class, () -> postMessage(null, true, port, 
false));
+        assertThrows(IOException.class, () -> sendMessage(null, true, port, 
false, HTTP_POST));
     }
 
     @Test
     public void 
testSecureServerTrustStoreNotConfiguredClientAuthenticationNotRequired() throws 
Exception {
         
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, 
serverNoTruststoreConfiguration);
         final int port = startSecureServer();
-        final int responseCode = postMessage(null, true, port, true);
+        final int responseCode = sendMessage(null, true, port, true, 
HTTP_POST);
         assertEquals(HttpServletResponse.SC_NO_CONTENT, responseCode);
     }
 
@@ -471,7 +476,7 @@ public class TestListenHTTP {
                 "\"3\",\"rec3\",\"103\"\n" +
                 "\"4\",\"rec4\",\"104\"\n";
 
-        startWebServerAndSendMessages(Collections.singletonList(""), 
HttpServletResponse.SC_OK, false, false);
+        startWebServerAndSendMessages(Collections.singletonList(""), 
HttpServletResponse.SC_OK, false, false, HTTP_POST);
         List<MockFlowFile> mockFlowFiles = 
runner.getFlowFilesForRelationship(RELATIONSHIP_SUCCESS);
 
         runner.assertTransferCount(RELATIONSHIP_SUCCESS, 1);
@@ -495,7 +500,7 @@ public class TestListenHTTP {
             parser.addRecord(keys.get(i), names.get(i), codes.get(i));
         }
 
-        startWebServerAndSendMessages(Collections.singletonList(""), 
HttpServletResponse.SC_BAD_REQUEST, false, false);
+        startWebServerAndSendMessages(Collections.singletonList(""), 
HttpServletResponse.SC_BAD_REQUEST, false, false, HTTP_POST);
 
         runner.assertTransferCount(RELATIONSHIP_SUCCESS, 0);
     }
@@ -533,6 +538,22 @@ public class TestListenHTTP {
         }
     }
 
+    @Test
+    public void testOptionsNotAllowed() throws Exception {
+        final List<String> messages = new ArrayList<>();
+        messages.add("payload 1");
+
+        startWebServerAndSendMessages(messages, 
HttpServletResponse.SC_METHOD_NOT_ALLOWED, false, false, HTTP_OPTIONS);
+    }
+
+    @Test
+    public void testTraceNotAllowed() throws Exception {
+        final List<String> messages = new ArrayList<>();
+        messages.add("payload 1");
+
+        startWebServerAndSendMessages(messages, 
HttpServletResponse.SC_METHOD_NOT_ALLOWED, false, false, HTTP_TRACE);
+    }
+
     private MockRecordParser setupRecordReaderTest() throws 
InitializationException {
         final MockRecordParser parser = new MockRecordParser();
         final MockRecordWriter writer = new MockRecordWriter();
@@ -556,16 +577,16 @@ public class TestListenHTTP {
         return startWebServer();
     }
 
-    private int postMessage(final String message, boolean secure, final int 
port, boolean clientAuthRequired) throws IOException {
-        final OkHttpClient okHttpClient = getOkHttpClient(secure, 
clientAuthRequired);
-        final Request.Builder requestBuilder = new Request.Builder();
-        final String url = buildUrl(secure, port);
-        requestBuilder.url(url);
-
+    private int sendMessage(final String message, final boolean secure, final 
int port, boolean clientAuthRequired, final String httpMethod) throws 
IOException {
         final byte[] bytes = message == null ? new byte[]{} : 
message.getBytes(StandardCharsets.UTF_8);
         final RequestBody requestBody = RequestBody.create(bytes, 
APPLICATION_OCTET_STREAM);
-        final Request request = requestBuilder.post(requestBody).build();
+        final String url = buildUrl(secure, port);
+        final Request.Builder requestBuilder = new Request.Builder();
+        final Request request = requestBuilder.method(httpMethod, requestBody)
+                .url(url)
+                .build();
 
+        final OkHttpClient okHttpClient = getOkHttpClient(secure, 
clientAuthRequired);
         try (final Response response = 
okHttpClient.newCall(request).execute()) {
             return response.code();
         }
@@ -597,7 +618,7 @@ public class TestListenHTTP {
         messages.add(null);
         messages.add("payload 2");
 
-        startWebServerAndSendMessages(messages, returnCode, secure, twoWaySsl);
+        startWebServerAndSendMessages(messages, returnCode, secure, twoWaySsl, 
HTTP_POST);
 
         List<MockFlowFile> mockFlowFiles = 
runner.getFlowFilesForRelationship(RELATIONSHIP_SUCCESS);
 
@@ -647,11 +668,12 @@ public class TestListenHTTP {
         return listeningPort;
     }
 
-    private void startWebServerAndSendMessages(final List<String> messages, 
final int expectedStatusCode, final boolean secure, final boolean 
clientAuthRequired) throws Exception {
+    private void startWebServerAndSendMessages(final List<String> messages, 
final int expectedStatusCode, final boolean secure, final boolean 
clientAuthRequired,
+                                               final String httpMethod) throws 
Exception {
         final int port = startWebServer();
 
         for (final String message : messages) {
-            final int statusCode = postMessage(message, secure, port, 
clientAuthRequired);
+            final int statusCode = sendMessage(message, secure, port, 
clientAuthRequired, httpMethod);
             assertEquals(expectedStatusCode, statusCode, "HTTP Status Code not 
matched");
         }
     }

Reply via email to