knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject [16/16] knox git commit: KNOX-998 - Bring branch up to speed with 0.14.0 RC1
Date Mon, 13 Nov 2017 15:48:06 GMT
KNOX-998 - Bring branch up to speed with 0.14.0 RC1


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

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: e70904b3d32af5df4c55f652187eda6b3719ab37
Parents: 2c69152
Author: Sandeep More <more@apache.org>
Authored: Mon Nov 13 10:47:33 2017 -0500
Committer: Sandeep More <more@apache.org>
Committed: Mon Nov 13 10:47:33 2017 -0500

----------------------------------------------------------------------
 gateway-adapter/pom.xml                         |   2 +-
 .../service/admin/TopologiesResource.java       |   2 +-
 .../resources/services/nifi/1.4.0/service.xml   |   2 +-
 .../hadoop/gateway/dispatch/NiFiDispatch.java   | 106 ------------------
 .../hadoop/gateway/dispatch/NiFiHaDispatch.java | 111 -------------------
 .../hadoop/gateway/dispatch/NiFiHeaders.java    |  26 -----
 .../gateway/dispatch/NiFiRequestUtil.java       |  89 ---------------
 .../gateway/dispatch/NiFiResponseUtil.java      |  89 ---------------
 .../knox/gateway/dispatch/NiFiDispatch.java     | 106 ++++++++++++++++++
 .../knox/gateway/dispatch/NiFiHaDispatch.java   | 111 +++++++++++++++++++
 .../knox/gateway/dispatch/NiFiHeaders.java      |  26 +++++
 .../knox/gateway/dispatch/NiFiRequestUtil.java  |  89 +++++++++++++++
 .../knox/gateway/dispatch/NiFiResponseUtil.java |  88 +++++++++++++++
 .../src/test/resources/log4j.properties         |   2 +-
 14 files changed, 424 insertions(+), 425 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-adapter/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-adapter/pom.xml b/gateway-adapter/pom.xml
index 4bb62e3..d6bd49e 100644
--- a/gateway-adapter/pom.xml
+++ b/gateway-adapter/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>gateway</artifactId>
         <groupId>org.apache.knox</groupId>
-        <version>0.14.0-SNAPSHOT</version>
+        <version>1.0.0-SNAPSHOT</version>
     </parent>
     <artifactId>gateway-adapter</artifactId>
     <name>gateway-adapter</name>

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
----------------------------------------------------------------------
diff --git a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
index 9ecd7fc..f960734 100644
--- a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
+++ b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
@@ -145,7 +145,7 @@ public class TopologiesResource {
 
     // Check for existing topology with the same name, to see if it had been generated
     boolean existingGenerated = false;
-    for (org.apache.hadoop.gateway.topology.Topology existingTopology : ts.getTopologies()) {
+    for (org.apache.knox.gateway.topology.Topology existingTopology : ts.getTopologies()) {
       if(existingTopology.getName().equals(id)) {
         existingGenerated = existingTopology.isGenerated();
         break;

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-definitions/src/main/resources/services/nifi/1.4.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/nifi/1.4.0/service.xml b/gateway-service-definitions/src/main/resources/services/nifi/1.4.0/service.xml
index 2ccc10d..d600e2d 100644
--- a/gateway-service-definitions/src/main/resources/services/nifi/1.4.0/service.xml
+++ b/gateway-service-definitions/src/main/resources/services/nifi/1.4.0/service.xml
@@ -26,5 +26,5 @@
             <rewrite apply="NIFI/nifi/inbound/path/query-other" to="request.url"/>
         </route>
     </routes>
-    <dispatch classname="org.apache.hadoop.gateway.dispatch.NiFiDispatch" ha-classname="org.apache.hadoop.gateway.dispatch.NiFiHaDispatch" />
+    <dispatch classname="org.apache.knox.gateway.dispatch.NiFiDispatch" ha-classname="org.apache.knox.gateway.dispatch.NiFiHaDispatch" />
 </service>

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiDispatch.java b/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiDispatch.java
deleted file mode 100644
index 013fd9c..0000000
--- a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiDispatch.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.hadoop.gateway.dispatch;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.hadoop.gateway.util.MimeTypes;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.entity.ContentType;
-
-public class NiFiDispatch extends DefaultDispatch {
-
-  @Override
-  protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
-    outboundRequest = NiFiRequestUtil.modifyOutboundRequest(outboundRequest, inboundRequest);
-    HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
-    writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
-  }
-
-  /**
-   * Overridden to provide a spot to modify the outbound response before its stream is closed.
-   */
-  protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
-    // Copy the client respond header to the server respond.
-    outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode());
-    Header[] headers = inboundResponse.getAllHeaders();
-    Set<String> excludeHeaders = getOutboundResponseExcludeHeaders();
-    boolean hasExcludeHeaders = false;
-    if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) {
-      hasExcludeHeaders = true;
-    }
-    for ( Header header : headers ) {
-      String name = header.getName();
-      if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) {
-        continue;
-      }
-      String value = header.getValue();
-      outboundResponse.addHeader(name, value);
-    }
-
-    HttpEntity entity = inboundResponse.getEntity();
-    if( entity != null ) {
-      outboundResponse.setContentType( getInboundResponseContentType( entity ) );
-      InputStream stream = entity.getContent();
-      try {
-        NiFiResponseUtil.modifyOutboundResponse(inboundRequest, outboundResponse, inboundResponse);
-        writeResponse( inboundRequest, outboundResponse, stream );
-      } finally {
-        closeInboundResponse( inboundResponse, stream );
-      }
-    }
-  }
-
-  /**
-   * Overriden due to {@link DefaultDispatch#getInboundResponseContentType(HttpEntity) having private access, and the method is used by
-   * {@link #writeOutboundResponse(HttpUriRequest, HttpServletRequest, HttpServletResponse, HttpResponse)}}
-   */
-  private String getInboundResponseContentType( final HttpEntity entity ) {
-    String fullContentType = null;
-    if( entity != null ) {
-      ContentType entityContentType = ContentType.get( entity );
-      if( entityContentType != null ) {
-        if( entityContentType.getCharset() == null ) {
-          final String entityMimeType = entityContentType.getMimeType();
-          final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType( entityMimeType );
-          if( defaultCharset != null ) {
-            LOG.usingDefaultCharsetForEntity( entityMimeType, defaultCharset );
-            entityContentType = entityContentType.withCharset( defaultCharset );
-          }
-        } else {
-          LOG.usingExplicitCharsetForEntity( entityContentType.getMimeType(), entityContentType.getCharset() );
-        }
-        fullContentType = entityContentType.toString();
-      }
-    }
-    if( fullContentType == null ) {
-      LOG.unknownResponseEntityContentType();
-    } else {
-      LOG.inboundResponseEntityContentType( fullContentType );
-    }
-    return fullContentType;
-  }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHaDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHaDispatch.java b/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHaDispatch.java
deleted file mode 100644
index 4272086..0000000
--- a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHaDispatch.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.hadoop.gateway.dispatch;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.hadoop.gateway.ha.dispatch.DefaultHaDispatch;
-import org.apache.hadoop.gateway.util.MimeTypes;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.entity.ContentType;
-
-public class NiFiHaDispatch extends DefaultHaDispatch {
-
-  public NiFiHaDispatch() {
-    setServiceRole("NIFI");
-  }
-
-  @Override
-  protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
-    outboundRequest = NiFiRequestUtil.modifyOutboundRequest(outboundRequest, inboundRequest);
-    HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
-    writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
-  }
-
-  /**
-   * Overridden to provide a spot to modify the outbound response before its stream is closed.
-   */
-  protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
-    // Copy the client respond header to the server respond.
-    outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode());
-    Header[] headers = inboundResponse.getAllHeaders();
-    Set<String> excludeHeaders = getOutboundResponseExcludeHeaders();
-    boolean hasExcludeHeaders = false;
-    if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) {
-      hasExcludeHeaders = true;
-    }
-    for ( Header header : headers ) {
-      String name = header.getName();
-      if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) {
-        continue;
-      }
-      String value = header.getValue();
-      outboundResponse.addHeader(name, value);
-    }
-
-    HttpEntity entity = inboundResponse.getEntity();
-    if( entity != null ) {
-      outboundResponse.setContentType( getInboundResponseContentType( entity ) );
-      InputStream stream = entity.getContent();
-      try {
-        NiFiResponseUtil.modifyOutboundResponse(inboundRequest, outboundResponse, inboundResponse);
-        writeResponse( inboundRequest, outboundResponse, stream );
-      } finally {
-        closeInboundResponse( inboundResponse, stream );
-      }
-    }
-  }
-
-  /**
-   * Overriden due to {@link DefaultDispatch#getInboundResponseContentType(HttpEntity) having private access, and the method is used by
-   * {@link #writeOutboundResponse(HttpUriRequest, HttpServletRequest, HttpServletResponse, HttpResponse)}}
-   */
-  private String getInboundResponseContentType( final HttpEntity entity ) {
-    String fullContentType = null;
-    if( entity != null ) {
-      ContentType entityContentType = ContentType.get( entity );
-      if( entityContentType != null ) {
-        if( entityContentType.getCharset() == null ) {
-          final String entityMimeType = entityContentType.getMimeType();
-          final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType( entityMimeType );
-          if( defaultCharset != null ) {
-            DefaultDispatch.LOG.usingDefaultCharsetForEntity( entityMimeType, defaultCharset );
-            entityContentType = entityContentType.withCharset( defaultCharset );
-          }
-        } else {
-          DefaultDispatch.LOG.usingExplicitCharsetForEntity( entityContentType.getMimeType(), entityContentType.getCharset() );
-        }
-        fullContentType = entityContentType.toString();
-      }
-    }
-    if( fullContentType == null ) {
-      DefaultDispatch.LOG.unknownResponseEntityContentType();
-    } else {
-      DefaultDispatch.LOG.inboundResponseEntityContentType( fullContentType );
-    }
-    return fullContentType;
-  }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHeaders.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHeaders.java b/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHeaders.java
deleted file mode 100644
index f3e8e68..0000000
--- a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiHeaders.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.hadoop.gateway.dispatch;
-
-class NiFiHeaders {
-  static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
-  static final String X_FORWARDED_HOST = "X-Forwarded-Server";
-  static final String X_FORWARDED_PORT = "X-Forwarded-Port";
-  static final String X_FORWARDED_CONTEXT = "X-Forwarded-Context";
-  static final String X_PROXIED_ENTITIES_CHAIN = "X-ProxiedEntitiesChain";
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiRequestUtil.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiRequestUtil.java b/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiRequestUtil.java
deleted file mode 100644
index 9fdc425..0000000
--- a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiRequestUtil.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.hadoop.gateway.dispatch;
-
-import java.io.IOException;
-
-import javax.security.auth.Subject;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.gateway.security.SubjectUtils;
-import org.apache.http.Header;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.methods.RequestBuilder;
-import org.apache.log4j.Logger;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Strings;
-
-class NiFiRequestUtil {
-
-  static HttpUriRequest modifyOutboundRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest) throws IOException {
-    // preserve trailing slash from inbound request in the outbound request
-    if (inboundRequest.getPathInfo().endsWith("/")) {
-      String[] split = outboundRequest.getURI().toString().split("\\?");
-      if (!split[0].endsWith("/")) {
-        outboundRequest = RequestBuilder.copy(outboundRequest).setUri(split[0] + "/" + (split.length == 2 ? "?" + split[1] : "")).build();
-      }
-    }
-    // update the X-Forwarded-Context header to include the Knox-specific context path
-    final Header originalXForwardedContextHeader = outboundRequest.getFirstHeader(NiFiHeaders.X_FORWARDED_CONTEXT);
-    if (originalXForwardedContextHeader != null) {
-      String xForwardedContextHeaderValue = originalXForwardedContextHeader.getValue();
-      if (!Strings.isNullOrEmpty(xForwardedContextHeaderValue)) {
-        // Inspect the inbound request and outbound request to determine the additional context path from the rewrite
-        // rules that needs to be added to the X-Forwarded-Context header to allow proper proxying to NiFi.
-        //
-        // NiFi does its own URL rewriting, and will not work with the context path provided by Knox
-        // (ie, "/gateway/sandbox").
-        //
-        // For example, if Knox has a rewrite rule "*://*:*/**/nifi-app/{**}?{**}", "/nifi-app" needs to be added
-        // to the existing value of the X-Forwarded-Context header, which ends up being "/gateway/sandbox/nifi-app".
-        String inboundRequestPathInfo = inboundRequest.getPathInfo();
-        String outboundRequestUriPath = outboundRequest.getURI().getPath();
-        String outboundRequestUriPathNoTrailingSlash = StringUtils.removeEnd(outboundRequestUriPath, "/");
-        String knoxRouteContext = null;
-        int index = inboundRequestPathInfo.lastIndexOf(outboundRequestUriPathNoTrailingSlash);
-        if (index >= 0) {
-          knoxRouteContext = inboundRequestPathInfo.substring(0, index);
-        } else {
-          Logger.getLogger(NiFiHaDispatch.class.getName()).error(String.format("Unable to find index of %s in %s", outboundRequestUriPathNoTrailingSlash, inboundRequestPathInfo));
-        }
-        outboundRequest.setHeader(NiFiHeaders.X_FORWARDED_CONTEXT, xForwardedContextHeaderValue + knoxRouteContext);
-      }
-    }
-
-    // NiFi requires the header "X-ProxiedEntitiesChain" to be set with the identity or identities of the authenticated requester.
-    // The effective principal (identity) in the requester subject must be added to "X-ProxiedEntitiesChain".
-    // If the request already has a populated "X-ProxiedEntitiesChain" header, the identities must be appended to it.
-    // If the user proxied through Knox is anonymous, the "Anonymous" identity needs to be represented in X-ProxiedEntitiesChain
-    // as empty angle brackets "<>".
-    final Subject subject = SubjectUtils.getCurrentSubject();
-    String effectivePrincipalName = SubjectUtils.getEffectivePrincipalName(subject);
-    outboundRequest.setHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN, Objects.firstNonNull(inboundRequest.getHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN), "") +
-        String.format("<%s>", effectivePrincipalName.equalsIgnoreCase("anonymous") ? "" : effectivePrincipalName));
-
-    // Make sure headers named "Cookie" are removed from the request to NiFi, since NiFi does not use cookies.
-    Header[] cookieHeaders = outboundRequest.getHeaders("Cookie");
-    for (Header cookieHeader : cookieHeaders) {
-      outboundRequest.removeHeader(cookieHeader);
-    }
-    return outboundRequest;
-  }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiResponseUtil.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiResponseUtil.java b/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiResponseUtil.java
deleted file mode 100644
index 38c98b3..0000000
--- a/gateway-service-nifi/src/main/java/org/apache/hadoop/gateway/dispatch/NiFiResponseUtil.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.hadoop.gateway.dispatch;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URIBuilder;
-
-class NiFiResponseUtil {
-
-  static void modifyOutboundResponse(HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
-    // Only want to rewrite the Location header on a HTTP 302
-    if (inboundResponse.getStatusLine().getStatusCode() == HttpServletResponse.SC_FOUND) {
-      Header originalLocationHeader = inboundResponse.getFirstHeader("Location");
-      if (originalLocationHeader != null) {
-        String originalLocation = originalLocationHeader.getValue();
-        URIBuilder originalLocationUriBuilder;
-        try {
-          originalLocationUriBuilder = new URIBuilder(originalLocation);
-        } catch (URISyntaxException e) {
-          throw new RuntimeException("Unable to parse URI from Location header", e);
-        }
-        URIBuilder inboundRequestUriBuilder = null;
-        try {
-          inboundRequestUriBuilder = new URIBuilder(inboundRequest.getRequestURI());
-        } catch (URISyntaxException e) {
-          throw new RuntimeException("Unable to parse the inbound request URI", e);
-        }
-        /*
-         * if the path specified in the Location header fron the inbound response contains the inbound request's URI's path,
-         * then it's going to the same web context, and the Location header should be updated based on the X_FORWARDED_* headers.
-         */
-        String inboundRequestUriPath = inboundRequestUriBuilder.getPath();
-        String originalLocationUriPath = originalLocationUriBuilder.getPath();
-        if (originalLocationUriPath.contains(inboundRequestUriPath)) {
-          // check for trailing slash of Location header if it exists and preserve it
-          final String trailingSlash = originalLocationUriPath.endsWith("/") ? "/" : "";
-          // retain query params
-          final List<NameValuePair> queryParams = originalLocationUriBuilder.getQueryParams();
-
-          // check for proxy settings
-          final String scheme = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_PROTO);
-          final String host = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_HOST);
-          final String port = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_PORT);
-
-          final String baseContextPath = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_CONTEXT);
-          final String pathInfo = inboundRequest.getPathInfo();
-
-          try {
-            final URI newLocation = new URIBuilder().setScheme(scheme).setHost(host).setPort((StringUtils.isNumeric(port) ? Integer.parseInt(port) : -1)).setPath(
-                baseContextPath + pathInfo + trailingSlash).setParameters(queryParams).build();
-            outboundResponse.setHeader("Location", newLocation.toString());
-          } catch (URISyntaxException e) {
-            throw new RuntimeException("Unable to rewrite Location header in response", e);
-          }
-        }
-      } else {
-        throw new RuntimeException("Received HTTP 302, but response is missing Location header");
-      }
-    }
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiDispatch.java b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiDispatch.java
new file mode 100644
index 0000000..d939180
--- /dev/null
+++ b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiDispatch.java
@@ -0,0 +1,106 @@
+/*
+ * 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.knox.gateway.dispatch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.knox.gateway.util.MimeTypes;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
+
+public class NiFiDispatch extends DefaultDispatch {
+
+  @Override
+  protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
+    outboundRequest = NiFiRequestUtil.modifyOutboundRequest(outboundRequest, inboundRequest);
+    HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
+    writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+  }
+
+  /**
+   * Overridden to provide a spot to modify the outbound response before its stream is closed.
+   */
+  protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
+    // Copy the client respond header to the server respond.
+    outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode());
+    Header[] headers = inboundResponse.getAllHeaders();
+    Set<String> excludeHeaders = getOutboundResponseExcludeHeaders();
+    boolean hasExcludeHeaders = false;
+    if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) {
+      hasExcludeHeaders = true;
+    }
+    for ( Header header : headers ) {
+      String name = header.getName();
+      if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) {
+        continue;
+      }
+      String value = header.getValue();
+      outboundResponse.addHeader(name, value);
+    }
+
+    HttpEntity entity = inboundResponse.getEntity();
+    if( entity != null ) {
+      outboundResponse.setContentType( getInboundResponseContentType( entity ) );
+      InputStream stream = entity.getContent();
+      try {
+        NiFiResponseUtil.modifyOutboundResponse(inboundRequest, outboundResponse, inboundResponse);
+        writeResponse( inboundRequest, outboundResponse, stream );
+      } finally {
+        closeInboundResponse( inboundResponse, stream );
+      }
+    }
+  }
+
+  /**
+   * Overriden due to {@link DefaultDispatch#getInboundResponseContentType(HttpEntity) having private access, and the method is used by
+   * {@link #writeOutboundResponse(HttpUriRequest, HttpServletRequest, HttpServletResponse, HttpResponse)}}
+   */
+  private String getInboundResponseContentType( final HttpEntity entity ) {
+    String fullContentType = null;
+    if( entity != null ) {
+      ContentType entityContentType = ContentType.get( entity );
+      if( entityContentType != null ) {
+        if( entityContentType.getCharset() == null ) {
+          final String entityMimeType = entityContentType.getMimeType();
+          final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType( entityMimeType );
+          if( defaultCharset != null ) {
+            LOG.usingDefaultCharsetForEntity( entityMimeType, defaultCharset );
+            entityContentType = entityContentType.withCharset( defaultCharset );
+          }
+        } else {
+          LOG.usingExplicitCharsetForEntity( entityContentType.getMimeType(), entityContentType.getCharset() );
+        }
+        fullContentType = entityContentType.toString();
+      }
+    }
+    if( fullContentType == null ) {
+      LOG.unknownResponseEntityContentType();
+    } else {
+      LOG.inboundResponseEntityContentType( fullContentType );
+    }
+    return fullContentType;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHaDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHaDispatch.java b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHaDispatch.java
new file mode 100644
index 0000000..5e1e3a0
--- /dev/null
+++ b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHaDispatch.java
@@ -0,0 +1,111 @@
+/*
+ * 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.knox.gateway.dispatch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.knox.gateway.ha.dispatch.DefaultHaDispatch;
+import org.apache.knox.gateway.util.MimeTypes;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
+
+public class NiFiHaDispatch extends DefaultHaDispatch {
+
+  public NiFiHaDispatch() {
+    setServiceRole("NIFI");
+  }
+
+  @Override
+  protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
+    outboundRequest = NiFiRequestUtil.modifyOutboundRequest(outboundRequest, inboundRequest);
+    HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
+    writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+  }
+
+  /**
+   * Overridden to provide a spot to modify the outbound response before its stream is closed.
+   */
+  protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
+    // Copy the client respond header to the server respond.
+    outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode());
+    Header[] headers = inboundResponse.getAllHeaders();
+    Set<String> excludeHeaders = getOutboundResponseExcludeHeaders();
+    boolean hasExcludeHeaders = false;
+    if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) {
+      hasExcludeHeaders = true;
+    }
+    for ( Header header : headers ) {
+      String name = header.getName();
+      if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) {
+        continue;
+      }
+      String value = header.getValue();
+      outboundResponse.addHeader(name, value);
+    }
+
+    HttpEntity entity = inboundResponse.getEntity();
+    if( entity != null ) {
+      outboundResponse.setContentType( getInboundResponseContentType( entity ) );
+      InputStream stream = entity.getContent();
+      try {
+        NiFiResponseUtil.modifyOutboundResponse(inboundRequest, outboundResponse, inboundResponse);
+        writeResponse( inboundRequest, outboundResponse, stream );
+      } finally {
+        closeInboundResponse( inboundResponse, stream );
+      }
+    }
+  }
+
+  /**
+   * Overriden due to {@link DefaultDispatch#getInboundResponseContentType(HttpEntity) having private access, and the method is used by
+   * {@link #writeOutboundResponse(HttpUriRequest, HttpServletRequest, HttpServletResponse, HttpResponse)}}
+   */
+  private String getInboundResponseContentType( final HttpEntity entity ) {
+    String fullContentType = null;
+    if( entity != null ) {
+      ContentType entityContentType = ContentType.get( entity );
+      if( entityContentType != null ) {
+        if( entityContentType.getCharset() == null ) {
+          final String entityMimeType = entityContentType.getMimeType();
+          final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType( entityMimeType );
+          if( defaultCharset != null ) {
+            DefaultDispatch.LOG.usingDefaultCharsetForEntity( entityMimeType, defaultCharset );
+            entityContentType = entityContentType.withCharset( defaultCharset );
+          }
+        } else {
+          DefaultDispatch.LOG.usingExplicitCharsetForEntity( entityContentType.getMimeType(), entityContentType.getCharset() );
+        }
+        fullContentType = entityContentType.toString();
+      }
+    }
+    if( fullContentType == null ) {
+      DefaultDispatch.LOG.unknownResponseEntityContentType();
+    } else {
+      DefaultDispatch.LOG.inboundResponseEntityContentType( fullContentType );
+    }
+    return fullContentType;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHeaders.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHeaders.java b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHeaders.java
new file mode 100644
index 0000000..2de967e
--- /dev/null
+++ b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiHeaders.java
@@ -0,0 +1,26 @@
+/*
+ * 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.knox.gateway.dispatch;
+
+class NiFiHeaders {
+  static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
+  static final String X_FORWARDED_HOST = "X-Forwarded-Server";
+  static final String X_FORWARDED_PORT = "X-Forwarded-Port";
+  static final String X_FORWARDED_CONTEXT = "X-Forwarded-Context";
+  static final String X_PROXIED_ENTITIES_CHAIN = "X-ProxiedEntitiesChain";
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiRequestUtil.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiRequestUtil.java b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiRequestUtil.java
new file mode 100644
index 0000000..7df3a09
--- /dev/null
+++ b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiRequestUtil.java
@@ -0,0 +1,89 @@
+/*
+ * 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.knox.gateway.dispatch;
+
+import java.io.IOException;
+
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.knox.gateway.security.SubjectUtils;
+import org.apache.http.Header;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.log4j.Logger;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+
+class NiFiRequestUtil {
+
+  static HttpUriRequest modifyOutboundRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest) throws IOException {
+    // preserve trailing slash from inbound request in the outbound request
+    if (inboundRequest.getPathInfo().endsWith("/")) {
+      String[] split = outboundRequest.getURI().toString().split("\\?");
+      if (!split[0].endsWith("/")) {
+        outboundRequest = RequestBuilder.copy(outboundRequest).setUri(split[0] + "/" + (split.length == 2 ? "?" + split[1] : "")).build();
+      }
+    }
+    // update the X-Forwarded-Context header to include the Knox-specific context path
+    final Header originalXForwardedContextHeader = outboundRequest.getFirstHeader(NiFiHeaders.X_FORWARDED_CONTEXT);
+    if (originalXForwardedContextHeader != null) {
+      String xForwardedContextHeaderValue = originalXForwardedContextHeader.getValue();
+      if (!Strings.isNullOrEmpty(xForwardedContextHeaderValue)) {
+        // Inspect the inbound request and outbound request to determine the additional context path from the rewrite
+        // rules that needs to be added to the X-Forwarded-Context header to allow proper proxying to NiFi.
+        //
+        // NiFi does its own URL rewriting, and will not work with the context path provided by Knox
+        // (ie, "/gateway/sandbox").
+        //
+        // For example, if Knox has a rewrite rule "*://*:*/**/nifi-app/{**}?{**}", "/nifi-app" needs to be added
+        // to the existing value of the X-Forwarded-Context header, which ends up being "/gateway/sandbox/nifi-app".
+        String inboundRequestPathInfo = inboundRequest.getPathInfo();
+        String outboundRequestUriPath = outboundRequest.getURI().getPath();
+        String outboundRequestUriPathNoTrailingSlash = StringUtils.removeEnd(outboundRequestUriPath, "/");
+        String knoxRouteContext = null;
+        int index = inboundRequestPathInfo.lastIndexOf(outboundRequestUriPathNoTrailingSlash);
+        if (index >= 0) {
+          knoxRouteContext = inboundRequestPathInfo.substring(0, index);
+        } else {
+          Logger.getLogger(NiFiHaDispatch.class.getName()).error(String.format("Unable to find index of %s in %s", outboundRequestUriPathNoTrailingSlash, inboundRequestPathInfo));
+        }
+        outboundRequest.setHeader(NiFiHeaders.X_FORWARDED_CONTEXT, xForwardedContextHeaderValue + knoxRouteContext);
+      }
+    }
+
+    // NiFi requires the header "X-ProxiedEntitiesChain" to be set with the identity or identities of the authenticated requester.
+    // The effective principal (identity) in the requester subject must be added to "X-ProxiedEntitiesChain".
+    // If the request already has a populated "X-ProxiedEntitiesChain" header, the identities must be appended to it.
+    // If the user proxied through Knox is anonymous, the "Anonymous" identity needs to be represented in X-ProxiedEntitiesChain
+    // as empty angle brackets "<>".
+    final Subject subject = SubjectUtils.getCurrentSubject();
+    String effectivePrincipalName = SubjectUtils.getEffectivePrincipalName(subject);
+    outboundRequest.setHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN, Objects.firstNonNull(inboundRequest.getHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN), "") +
+        String.format("<%s>", effectivePrincipalName.equalsIgnoreCase("anonymous") ? "" : effectivePrincipalName));
+
+    // Make sure headers named "Cookie" are removed from the request to NiFi, since NiFi does not use cookies.
+    Header[] cookieHeaders = outboundRequest.getHeaders("Cookie");
+    for (Header cookieHeader : cookieHeaders) {
+      outboundRequest.removeHeader(cookieHeader);
+    }
+    return outboundRequest;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiResponseUtil.java
----------------------------------------------------------------------
diff --git a/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiResponseUtil.java b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiResponseUtil.java
new file mode 100644
index 0000000..b2d9ebb
--- /dev/null
+++ b/gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiResponseUtil.java
@@ -0,0 +1,88 @@
+/*
+ * 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.knox.gateway.dispatch;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+
+class NiFiResponseUtil {
+
+  static void modifyOutboundResponse(HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
+    // Only want to rewrite the Location header on a HTTP 302
+    if (inboundResponse.getStatusLine().getStatusCode() == HttpServletResponse.SC_FOUND) {
+      Header originalLocationHeader = inboundResponse.getFirstHeader("Location");
+      if (originalLocationHeader != null) {
+        String originalLocation = originalLocationHeader.getValue();
+        URIBuilder originalLocationUriBuilder;
+        try {
+          originalLocationUriBuilder = new URIBuilder(originalLocation);
+        } catch (URISyntaxException e) {
+          throw new RuntimeException("Unable to parse URI from Location header", e);
+        }
+        URIBuilder inboundRequestUriBuilder = null;
+        try {
+          inboundRequestUriBuilder = new URIBuilder(inboundRequest.getRequestURI());
+        } catch (URISyntaxException e) {
+          throw new RuntimeException("Unable to parse the inbound request URI", e);
+        }
+        /*
+         * if the path specified in the Location header fron the inbound response contains the inbound request's URI's path,
+         * then it's going to the same web context, and the Location header should be updated based on the X_FORWARDED_* headers.
+         */
+        String inboundRequestUriPath = inboundRequestUriBuilder.getPath();
+        String originalLocationUriPath = originalLocationUriBuilder.getPath();
+        if (originalLocationUriPath.contains(inboundRequestUriPath)) {
+          // check for trailing slash of Location header if it exists and preserve it
+          final String trailingSlash = originalLocationUriPath.endsWith("/") ? "/" : "";
+          // retain query params
+          final List<NameValuePair> queryParams = originalLocationUriBuilder.getQueryParams();
+
+          // check for proxy settings
+          final String scheme = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_PROTO);
+          final String host = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_HOST);
+          final String port = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_PORT);
+
+          final String baseContextPath = inboundRequest.getHeader(NiFiHeaders.X_FORWARDED_CONTEXT);
+          final String pathInfo = inboundRequest.getPathInfo();
+
+          try {
+            final URI newLocation = new URIBuilder().setScheme(scheme).setHost(host).setPort((StringUtils.isNumeric(port) ? Integer.parseInt(port) : -1)).setPath(
+                baseContextPath + pathInfo + trailingSlash).setParameters(queryParams).build();
+            outboundResponse.setHeader("Location", newLocation.toString());
+          } catch (URISyntaxException e) {
+            throw new RuntimeException("Unable to rewrite Location header in response", e);
+          }
+        }
+      } else {
+        throw new RuntimeException("Received HTTP 302, but response is missing Location header");
+      }
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/knox/blob/e70904b3/gateway-test/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/resources/log4j.properties b/gateway-test/src/test/resources/log4j.properties
index e500707..f3ee344 100644
--- a/gateway-test/src/test/resources/log4j.properties
+++ b/gateway-test/src/test/resources/log4j.properties
@@ -24,7 +24,7 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=%5p [%c] %m%n
 
 #log4j.logger.org.apache.knox.gateway=DEBUG
-#log4j.logger.org.apache.hadoop.test=DEBUG
+#log4j.logger.org.apache.knox.test=DEBUG
 #log4j.logger.org.apache.knox.gateway.http=TRACE
 #log4j.logger.org.apache.knox.gateway.http.request.body=OFF
 #log4j.logger.org.apache.knox.gateway.http.response.body=OFF


Mime
View raw message