Repository: nifi
Updated Branches:
  refs/heads/0.x 86c96d930 -> ae0c82cec


NIFI-1937 GetHTTP configurable redirect cookie policy

Reviewed by Tony Kurc ([email protected]). This closes #479


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/ae0c82ce
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/ae0c82ce
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/ae0c82ce

Branch: refs/heads/0.x
Commit: ae0c82cecbf6ea6dd0f823f226dd49a5b9771752
Parents: 86c96d9
Author: Mike Moser <[email protected]>
Authored: Fri May 27 17:11:10 2016 -0400
Committer: Tony Kurc <[email protected]>
Committed: Sat Jun 11 11:08:01 2016 -0400

----------------------------------------------------------------------
 .../nifi/processors/standard/GetHTTP.java       | 45 ++++++++++++-
 .../standard/CookieTestingServlet.java          | 68 +++++++++++++++++++
 .../CookieVerificationTestingServlet.java       | 52 ++++++++++++++
 .../nifi/processors/standard/TestGetHTTP.java   | 71 ++++++++++++++++++++
 4 files changed, 234 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/ae0c82ce/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java
index 438e3b9..0695526 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java
@@ -72,6 +72,7 @@ import org.apache.nifi.annotation.behavior.WritesAttributes;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.AllowableValue;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.ValidationContext;
 import org.apache.nifi.components.ValidationResult;
@@ -197,6 +198,30 @@ public class GetHTTP extends 
AbstractSessionFactoryProcessor {
             .addValidator(StandardValidators.PORT_VALIDATOR)
             .build();
 
+    public static final String DEFAULT_COOKIE_POLICY_STR = "default";
+    public static final String STANDARD_COOKIE_POLICY_STR = "standard";
+    public static final String STRICT_COOKIE_POLICY_STR = "strict";
+    public static final String NETSCAPE_COOKIE_POLICY_STR = "netscape";
+    public static final String IGNORE_COOKIE_POLICY_STR = "ignore";
+    public static final AllowableValue DEFAULT_COOKIE_POLICY = new 
AllowableValue(DEFAULT_COOKIE_POLICY_STR, DEFAULT_COOKIE_POLICY_STR,
+            "Default cookie policy that provides a higher degree of 
compatibility with common cookie management of popular HTTP agents for 
non-standard (Netscape style) cookies.");
+    public static final AllowableValue STANDARD_COOKIE_POLICY = new 
AllowableValue(STANDARD_COOKIE_POLICY_STR, STANDARD_COOKIE_POLICY_STR,
+            "RFC 6265 compliant cookie policy (interoperability profile).");
+    public static final AllowableValue STRICT_COOKIE_POLICY = new 
AllowableValue(STRICT_COOKIE_POLICY_STR, STRICT_COOKIE_POLICY_STR,
+            "RFC 6265 compliant cookie policy (strict profile).");
+    public static final AllowableValue NETSCAPE_COOKIE_POLICY = new 
AllowableValue(NETSCAPE_COOKIE_POLICY_STR, NETSCAPE_COOKIE_POLICY_STR,
+            "Netscape draft compliant cookie policy.");
+    public static final AllowableValue IGNORE_COOKIE_POLICY = new 
AllowableValue(IGNORE_COOKIE_POLICY_STR, IGNORE_COOKIE_POLICY_STR,
+            "A cookie policy that ignores cookies.");
+
+    public static final PropertyDescriptor REDIRECT_COOKIE_POLICY = new 
PropertyDescriptor.Builder()
+            .name("redirect-cookie-policy")
+            .displayName("Redirect Cookie Policy")
+            .description("When a HTTP server responds to a request with a 
redirect, this is the cookie policy used to copy cookies to the following 
request.")
+            .allowableValues(DEFAULT_COOKIE_POLICY, STANDARD_COOKIE_POLICY, 
STRICT_COOKIE_POLICY, NETSCAPE_COOKIE_POLICY, IGNORE_COOKIE_POLICY)
+            .defaultValue(DEFAULT_COOKIE_POLICY_STR)
+            .build();
+
     public static final Relationship REL_SUCCESS = new Relationship.Builder()
             .name("success")
             .description("All files are transferred to the success 
relationship")
@@ -231,6 +256,7 @@ public class GetHTTP extends 
AbstractSessionFactoryProcessor {
         properties.add(USER_AGENT);
         properties.add(ACCEPT_CONTENT_TYPE);
         properties.add(FOLLOW_REDIRECTS);
+        properties.add(REDIRECT_COOKIE_POLICY);
         properties.add(PROXY_HOST);
         properties.add(PROXY_PORT);
         this.properties = Collections.unmodifiableList(properties);
@@ -359,10 +385,25 @@ public class GetHTTP extends 
AbstractSessionFactoryProcessor {
             final RequestConfig.Builder requestConfigBuilder = 
RequestConfig.custom();
             
requestConfigBuilder.setConnectionRequestTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
             
requestConfigBuilder.setConnectTimeout(context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
-            requestConfigBuilder.setRedirectsEnabled(false);
             
requestConfigBuilder.setSocketTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
             
requestConfigBuilder.setRedirectsEnabled(context.getProperty(FOLLOW_REDIRECTS).asBoolean());
-            requestConfigBuilder.setCookieSpec(CookieSpecs.STANDARD);
+            switch (context.getProperty(REDIRECT_COOKIE_POLICY).getValue()) {
+            case STANDARD_COOKIE_POLICY_STR:
+                requestConfigBuilder.setCookieSpec(CookieSpecs.STANDARD);
+                break;
+            case STRICT_COOKIE_POLICY_STR:
+                
requestConfigBuilder.setCookieSpec(CookieSpecs.STANDARD_STRICT);
+                break;
+            case NETSCAPE_COOKIE_POLICY_STR:
+                requestConfigBuilder.setCookieSpec(CookieSpecs.NETSCAPE);
+                break;
+            case IGNORE_COOKIE_POLICY_STR:
+                requestConfigBuilder.setCookieSpec(CookieSpecs.IGNORE_COOKIES);
+                break;
+            case DEFAULT_COOKIE_POLICY_STR:
+            default:
+                requestConfigBuilder.setCookieSpec(CookieSpecs.DEFAULT);
+            }
 
             // build the http client
             final HttpClientBuilder clientBuilder = HttpClientBuilder.create();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae0c82ce/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieTestingServlet.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieTestingServlet.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieTestingServlet.java
new file mode 100644
index 0000000..fb7a5d1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieTestingServlet.java
@@ -0,0 +1,68 @@
+/*
+ * 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.processors.standard;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.DateGenerator;
+
+public class CookieTestingServlet extends HttpServlet {
+    public static final String DATEMODE_COOKIE_DEFAULT = "cookieDateDefault";
+    public static final String DATEMODE_COOKIE_NOT_TYPICAL = 
"cookieDateNotTypical";
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
+        String redirect = req.getParameter("redirect");
+        if (redirect == null) {
+            redirect = "null";
+        }
+
+        String dateMode = req.getParameter("datemode");
+        if (dateMode == null) {
+            dateMode = DATEMODE_COOKIE_DEFAULT;
+        }
+        switch (dateMode) {
+        case DATEMODE_COOKIE_DEFAULT:
+        default:
+            // standard way of building a cookie header date uses format "EEE, 
dd-MMM-yy HH:mm:ss z"
+            // this results in Set-Cookie: session=abc123; path=/; 
expires=EEE, dd-MMM-yy HH:mm:ss z; HttpOnly
+            Cookie cookie = new Cookie("session", "abc123");
+            cookie.setPath("/");
+            cookie.setHttpOnly(true);
+            cookie.setMaxAge(86400);
+            resp.addCookie(cookie);
+            break;
+
+        case DATEMODE_COOKIE_NOT_TYPICAL:
+            // hacked way of building a cookie header, to get less-often-used 
date format "EEE, dd MMM yy HH:mm:ss z"
+            // this results in Set-Cookie: session=abc123; path=/; 
expires=EEE, dd MMM yy HH:mm:ss z; HttpOnly
+            StringBuilder buf = new StringBuilder("session=abc123; path=/; 
expires=");
+            buf.append(DateGenerator.formatDate(System.currentTimeMillis() + 
1000L * 60 * 60 * 24));
+            buf.append("; HttpOnly");
+            resp.addHeader("Set-Cookie", buf.toString());
+        }
+
+        resp.sendRedirect(redirect);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae0c82ce/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieVerificationTestingServlet.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieVerificationTestingServlet.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieVerificationTestingServlet.java
new file mode 100644
index 0000000..5d959b7
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/CookieVerificationTestingServlet.java
@@ -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.processors.standard;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.nifi.stream.io.StreamUtils;
+
+public class CookieVerificationTestingServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(final HttpServletRequest req, final 
HttpServletResponse resp) throws ServletException, IOException {
+        Cookie[] cookies = req.getCookies();
+        if (cookies != null) {
+            for (Cookie cookie : cookies) {
+                if ("session".equals(cookie.getName())) {
+                    final ServletOutputStream out = resp.getOutputStream();
+                    try (final FileInputStream fis = new 
FileInputStream("src/test/resources/hello.txt")) {
+                        StreamUtils.copy(fis, out);
+                        return;
+                    }
+                }
+            }
+        }
+
+        // session cookie not found, error
+        resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Did not receive 
expected session cookie");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae0c82ce/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestGetHTTP.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestGetHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestGetHTTP.java
index 6402392..d07baa5 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestGetHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestGetHTTP.java
@@ -31,6 +31,7 @@ import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -398,6 +399,76 @@ public class TestGetHTTP {
         }
     }
 
+    @Test
+    public final void testCookiePolicy() throws Exception {
+        // set up web services
+        ServletHandler handler1 = new ServletHandler();
+        handler1.addServletWithMapping(CookieTestingServlet.class, "/*");
+
+        ServletHandler handler2 = new ServletHandler();
+        handler2.addServletWithMapping(CookieVerificationTestingServlet.class, 
"/*");
+
+        // create the services
+        TestServer server1 = new TestServer();
+        server1.addHandler(handler1);
+
+        TestServer server2 = new TestServer();
+        server2.addHandler(handler2);
+
+        try {
+            server1.startServer();
+            server2.startServer();
+
+            // this is the base urls with the random ports
+            String destination1 = server1.getUrl();
+            String destination2 = server2.getUrl();
+
+            // set up NiFi mock controller
+            controller = TestRunners.newTestRunner(GetHTTP.class);
+            controller.setProperty(GetHTTP.CONNECTION_TIMEOUT, "5 secs");
+            controller.setProperty(GetHTTP.URL, destination1 + "/?redirect=" + 
URLEncoder.encode(destination2, "UTF-8")
+                    + "&datemode=" + 
CookieTestingServlet.DATEMODE_COOKIE_DEFAULT);
+            controller.setProperty(GetHTTP.FILENAME, "testFile");
+            controller.setProperty(GetHTTP.FOLLOW_REDIRECTS, "true");
+
+            controller.run(1);
+
+            // verify default cookie data does successful redirect
+            controller.assertAllFlowFilesTransferred(GetHTTP.REL_SUCCESS, 1);
+            MockFlowFile ff = 
controller.getFlowFilesForRelationship(GetHTTP.REL_SUCCESS).get(0);
+            ff.assertContentEquals("Hello, World!");
+
+            controller.clearTransferState();
+
+            // verify NON-standard cookie data fails with default 
redirect_cookie_policy
+            controller.setProperty(GetHTTP.URL, destination1 + "/?redirect=" + 
URLEncoder.encode(destination2, "UTF-8")
+                    + "&datemode=" + 
CookieTestingServlet.DATEMODE_COOKIE_NOT_TYPICAL);
+
+            controller.run(1);
+
+            controller.assertAllFlowFilesTransferred(GetHTTP.REL_SUCCESS, 0);
+
+            controller.clearTransferState();
+
+            // change GetHTTP to place it in STANDARD cookie policy mode
+            controller.setProperty(GetHTTP.REDIRECT_COOKIE_POLICY, 
GetHTTP.STANDARD_COOKIE_POLICY_STR);
+            controller.setProperty(GetHTTP.URL, destination1 + "/?redirect=" + 
URLEncoder.encode(destination2, "UTF-8")
+                    + "&datemode=" + 
CookieTestingServlet.DATEMODE_COOKIE_NOT_TYPICAL);
+
+            controller.run(1);
+
+            // verify NON-standard cookie data does successful redirect
+            controller.assertAllFlowFilesTransferred(GetHTTP.REL_SUCCESS, 1);
+            ff = 
controller.getFlowFilesForRelationship(GetHTTP.REL_SUCCESS).get(0);
+            ff.assertContentEquals("Hello, World!");
+
+        } finally {
+            // shutdown web services
+            server1.shutdownServer();
+            server2.shutdownServer();
+        }
+    }
+
     private static Map<String, String> getTruststoreProperties() {
         final Map<String, String> props = new HashMap<>();
         props.put(StandardSSLContextService.TRUSTSTORE.getName(), 
"src/test/resources/localhost-ts.jks");

Reply via email to