You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2015/07/27 18:28:17 UTC

[2/2] knox git commit: KNOX-565: Supporting All the Quick Links on Ambari Dashboard to Go Through Knox

KNOX-565: Supporting All the Quick Links on Ambari Dashboard to Go Through Knox


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

Branch: refs/heads/master
Commit: be727f18c967ce78f4e290a2cdf4614738a65046
Parents: 611ffae
Author: Kevin Minder <ke...@hortonworks.com>
Authored: Mon Jul 27 12:20:13 2015 -0400
Committer: Kevin Minder <ke...@hortonworks.com>
Committed: Mon Jul 27 12:28:10 2015 -0400

----------------------------------------------------------------------
 .../rewrite/impl/UrlRewriteFilterReader.java    |  39 ++++
 .../filter/rewrite/impl/UrlRewriteResponse.java |  31 +++-
 .../filter/rewrite/impl/UrlRewriteUtil.java     |  34 ++++
 .../rewrite/impl/html/HtmlFilterReader.java     |   7 +
 .../rewrite/impl/html/HtmlFilterReaderBase.java |  30 +++-
 .../impl/html/HtmlUrlRewriteFilterReader.java   |   5 +-
 .../impl/javascript/JavaScriptFilterReader.java |  91 ++++++++++
 .../JavaScriptUrlRewriteFilterReader.java       |  62 +++++++
 .../JavaScriptUrlRewriteStreamFilter.java       |  63 +++++++
 ...ay.filter.rewrite.spi.UrlRewriteStreamFilter |   3 +-
 .../rewrite/impl/UrlRewriteResponseTest.java    |  63 +++++++
 .../impl/html/HtmlFilterReaderBaseTest.java     |  91 ++++++++++
 .../javascript/JavaScriptFilterReaderTest.java  | 118 +++++++++++++
 .../services/hbaseui/1.1.0/rewrite.xml          | 105 +++++++++++
 .../services/hbaseui/1.1.0/service.xml          |  45 +++++
 .../resources/services/hdfsui/2.7.0/rewrite.xml |  94 ++++++++++
 .../resources/services/hdfsui/2.7.0/service.xml |  39 ++++
 .../services/jobhistoryui/2.7.0/rewrite.xml     | 125 +++++++++++++
 .../services/jobhistoryui/2.7.0/service.xml     |  36 ++++
 .../services/oozieui/4.2.0/rewrite.xml          |  28 +++
 .../services/oozieui/4.2.0/service.xml          |  24 +++
 .../services/sparkhistoryui/1.4.0/rewrite.xml   | 104 +++++++++++
 .../services/sparkhistoryui/1.4.0/service.xml   |  33 ++++
 .../resources/services/yarnui/2.7.0/rewrite.xml | 176 +++++++++++++++++++
 .../resources/services/yarnui/2.7.0/service.xml |  42 +++++
 25 files changed, 1480 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFilterReader.java
new file mode 100644
index 0000000..c291468
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFilterReader.java
@@ -0,0 +1,39 @@
+/**
+ * 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.filter.rewrite.impl;
+
+import java.util.regex.Pattern;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+
+
+public interface UrlRewriteFilterReader {
+
+  public String filterValueString( String name, String value, String rule );
+
+  public static class RegexCompiler implements UrlRewriteFilterPathDescriptor.Compiler<Pattern> {
+    @Override
+    public Pattern compile( String expression, Pattern compiled ) {
+      if( compiled != null ) {
+        return compiled;
+      } else {
+        return Pattern.compile( expression );
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponse.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponse.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponse.java
index 9fbc68a..ef61ae1 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponse.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponse.java
@@ -37,6 +37,8 @@ import javax.servlet.FilterConfig;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -48,6 +50,9 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import java.util.zip.ZipException;
 
 import static org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteUtil.getRewriteFilterConfig;
 import static org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteUtil.pickFirstRuleWithEqualsIgnoreCasePathMatch;
@@ -143,13 +148,33 @@ public class UrlRewriteResponse extends GatewayResponseWrapper implements Params
 
   @Override
   public void streamResponse( InputStream input, OutputStream output ) throws IOException {
+    InputStream inStream;
+    OutputStream outStream;
+    boolean isGzip = false;
+    BufferedInputStream inBuffer = new BufferedInputStream(input);
+    try {
+      // Use this way to check whether the input stream is gzip compressed, in case
+      // the content encoding header is unknown, as it could be unset in inbound response
+      inBuffer.mark(STREAM_BUFFER_SIZE);
+      inStream = new GZIPInputStream(inBuffer);
+      isGzip = true;
+    } catch (ZipException e) {
+      inBuffer.reset();
+      inStream = inBuffer;
+    } catch (IOException e) {
+      inBuffer.reset();
+      inStream = inBuffer;
+    }
+
     MimeType mimeType = getMimeType();
     UrlRewriteFilterContentDescriptor filterContentConfig =
         getRewriteFilterConfig( rewriter.getConfig(), bodyFilterName, mimeType );
     InputStream filteredInput = UrlRewriteStreamFilterFactory.create(
-        mimeType, null, input, rewriter, this, UrlRewriter.Direction.OUT, filterContentConfig );
-    IOUtils.copyBytes( filteredInput, output, STREAM_BUFFER_SIZE );
-    output.close();
+        mimeType, null, inStream, rewriter, this, UrlRewriter.Direction.OUT, filterContentConfig );
+    outStream = (isGzip) ? new GZIPOutputStream(output) : output;
+    IOUtils.copyBytes( filteredInput, outStream, STREAM_BUFFER_SIZE );
+    outStream.flush();
+    outStream.close();
   }
 
   //TODO: Need to buffer the output here and when it is closed, rewrite it and then write the result to the stream.

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteUtil.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteUtil.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteUtil.java
index 6354afe..720b392 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteUtil.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteUtil.java
@@ -17,6 +17,9 @@
  */
 package org.apache.hadoop.gateway.filter.rewrite.impl;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterDescriptor;
@@ -55,4 +58,35 @@ public class UrlRewriteUtil {
     return filterContentConfig;
   }
 
+  public static String filterJavaScript( String inputValue, UrlRewriteFilterContentDescriptor config,
+      UrlRewriteFilterReader filterReader, UrlRewriteFilterPathDescriptor.Compiler<Pattern> regexCompiler ) {
+    StringBuffer tbuff = new StringBuffer();
+    StringBuffer sbuff = new StringBuffer();
+    sbuff.append( inputValue );
+    if( config != null && !config.getSelectors().isEmpty() ) {
+      for( UrlRewriteFilterPathDescriptor selector : config.getSelectors() ) {
+        if ( selector instanceof UrlRewriteFilterApplyDescriptor ) {
+          UrlRewriteFilterApplyDescriptor apply = (UrlRewriteFilterApplyDescriptor)selector;
+          Matcher matcher = apply.compiledPath( regexCompiler ).matcher( sbuff );
+          int index = 0;
+          while ( matcher.find() ) {
+            int start = matcher.start();
+            int end = matcher.end();
+            if ( start != -1 && end != -1 ) {
+              tbuff.append( sbuff, index, start );
+              String value = matcher.group();
+              value = filterReader.filterValueString( null, value, apply.rule() );
+              tbuff.append(value);
+              index = end;
+            }
+          }
+          tbuff.append( sbuff, index, sbuff.length() );
+          sbuff.setLength( 0 );
+          sbuff.append( tbuff );
+          tbuff.setLength( 0 );
+        }
+      }
+    }
+    return sbuff.toString();
+  }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
index c87e1bf..c61553e 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
@@ -19,6 +19,9 @@ package org.apache.hadoop.gateway.filter.rewrite.impl.html;
 
 import javax.xml.namespace.QName;
 import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+
 import java.io.IOException;
 import java.io.Reader;
 
@@ -37,6 +40,10 @@ public abstract class HtmlFilterReader extends HtmlFilterReaderBase {
     super( reader );
   }
 
+  public HtmlFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException, ParserConfigurationException {
+    super( reader, config );
+  }
+
   protected abstract String filterAttribute( String tagName, String attributeName, String attributeValue, String ruleName );
 
   protected abstract String filterText( String tagName, String text, String ruleName );

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
index b33d2e1..e2cf9be 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
@@ -24,7 +24,12 @@ import net.htmlparser.jericho.Segment;
 import net.htmlparser.jericho.StartTag;
 import net.htmlparser.jericho.StreamedSource;
 import net.htmlparser.jericho.Tag;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFilterReader;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteUtil;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -35,12 +40,20 @@ import javax.xml.parsers.ParserConfigurationException;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringWriter;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Stack;
+import java.util.regex.Pattern;
+
+public abstract class HtmlFilterReaderBase extends Reader implements UrlRewriteFilterReader {
 
-public abstract class HtmlFilterReaderBase extends Reader {
+  private static List<String> JSTYPES = Arrays.asList( new String[] { "application/javascritp", "text/javascript", "*/javascript",
+      "application/x-javascript", "text/x-javascript", "*/x-javascript" } );
+  private static final String SCRIPTTAG = "script";
+  private static final UrlRewriteFilterPathDescriptor.Compiler<Pattern> REGEX_COMPILER = new RegexCompiler();
 
   private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
 
@@ -53,6 +66,7 @@ public abstract class HtmlFilterReaderBase extends Reader {
   private int offset;
   private StringWriter writer;
   private StringBuffer buffer;
+  private UrlRewriteFilterContentDescriptor config = null;
 
   protected HtmlFilterReaderBase( Reader reader ) throws IOException, ParserConfigurationException {
     this.reader = reader;
@@ -65,6 +79,11 @@ public abstract class HtmlFilterReaderBase extends Reader {
     offset = 0;
   }
 
+  protected HtmlFilterReaderBase( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException, ParserConfigurationException {
+    this(reader);
+    this.config = config;
+  }
+
   protected abstract String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName );
 
   protected abstract String filterText( QName elementName, String text, String ruleName );
@@ -179,7 +198,14 @@ public abstract class HtmlFilterReaderBase extends Reader {
         // This can happen for whitespace outside of the root element.
         //outputValue = filterText( null, inputValue );
       } else {
-        outputValue = filterText( stack.peek().getQName(), inputValue, null );
+        String tagType = stack.peek().getTag().getAttributeValue("type");
+        String tagName = stack.peek().getTag().getName();
+        if (SCRIPTTAG.equals(tagName) && JSTYPES.contains(tagType) && config != null && !config.getSelectors().isEmpty() ) {
+          // embedded javascript content
+          outputValue = UrlRewriteUtil.filterJavaScript( inputValue, config, this, REGEX_COMPILER );
+        } else {
+          outputValue = filterText( stack.peek().getQName(), inputValue, null );
+        }
       }
       if( outputValue == null ) {
         outputValue = inputValue;

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
index 44fd6af..340d6d1 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
@@ -40,14 +40,15 @@ public class HtmlUrlRewriteFilterReader extends HtmlFilterReader {
 
   public HtmlUrlRewriteFilterReader( Reader reader, UrlRewriter rewriter, Resolver resolver, UrlRewriter.Direction direction, UrlRewriteFilterContentDescriptor config )
       throws IOException, ParserConfigurationException {
-    super( reader );
+    super( reader, config );
     this.resolver = resolver;
     this.rewriter = rewriter;
     this.direction = direction;
   }
 
   //TODO: Need to limit which values are attempted to be filtered by the name.
-  protected String filterValueString( String name, String value, String rule ) {
+  @Override
+  public String filterValueString( String name, String value, String rule ) {
     try {
       Template input = Parser.parse( value );
       Template output = rewriter.rewrite( resolver, input, direction, rule );

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java
new file mode 100644
index 0000000..46e630a
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java
@@ -0,0 +1,91 @@
+/**
+ * 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.filter.rewrite.impl.javascript;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFilterReader;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteUtil;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.regex.Pattern;
+
+public abstract class JavaScriptFilterReader extends Reader implements UrlRewriteFilterReader {
+
+  private static final UrlRewriteFilterPathDescriptor.Compiler<Pattern> REGEX_COMPILER = new RegexCompiler();
+
+  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+  private BufferedReader reader;
+  private int offset;
+  private StringWriter writer;
+  private StringBuffer buffer;
+  private UrlRewriteFilterContentDescriptor config;
+
+  protected JavaScriptFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
+    this.reader = new BufferedReader( reader );
+    this.config = config;
+    writer = new StringWriter();
+    buffer = writer.getBuffer();
+    offset = 0;
+  }
+
+  @Override
+  public abstract String filterValueString( String name, String value, String rule );
+
+  @Override
+  public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
+    int count = 0;
+    int available = buffer.length() - offset;
+    String cbuff;
+    if( available == 0 ) {
+      cbuff = reader.readLine();
+      if( cbuff != null ) {
+        count = cbuff.length();
+        writer.write( UrlRewriteUtil.filterJavaScript( cbuff, config, this, REGEX_COMPILER ) );
+        writer.write( '\n' );
+        available = buffer.length() - offset;
+      } else {
+        count = -1;
+      }
+    }
+
+    if( available > 0 ) {
+      count = Math.min( destCount, available );
+      buffer.getChars( offset, offset + count, destBuffer, destOffset );
+      offset += count;
+      if( offset == buffer.length() ) {
+        offset = 0;
+        buffer.setLength( 0 );
+      }
+    }
+
+    return count;
+  }
+
+  @Override
+  public void close() throws IOException {
+    reader.close();
+    writer.close();
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java
new file mode 100644
index 0000000..da54e22
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java
@@ -0,0 +1,62 @@
+/**
+ * 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.filter.rewrite.impl.javascript;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.util.urltemplate.Parser;
+import org.apache.hadoop.gateway.util.urltemplate.Resolver;
+import org.apache.hadoop.gateway.util.urltemplate.Template;
+
+public class JavaScriptUrlRewriteFilterReader extends JavaScriptFilterReader {
+
+  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+  private Resolver resolver;
+  private UrlRewriter rewriter;
+  private UrlRewriter.Direction direction;
+
+  public JavaScriptUrlRewriteFilterReader( Reader reader, UrlRewriter rewriter, Resolver resolver, UrlRewriter.Direction direction, UrlRewriteFilterContentDescriptor config )
+      throws IOException {
+    super( reader, config );
+    this.resolver = resolver;
+    this.rewriter = rewriter;
+    this.direction = direction;
+  }
+
+  @Override
+  public String filterValueString( String name, String value, String rule ) {
+    try {
+      Template input = Parser.parse( value );
+      Template output = rewriter.rewrite( resolver, input, direction, rule );
+      if( output != null ) {
+        value = output.getPattern();
+      }
+    } catch( URISyntaxException e ) {
+      LOG.failedToParseValueForUrlRewrite( value );
+    }
+    return value;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..0259649
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
@@ -0,0 +1,63 @@
+/**
+ * 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.filter.rewrite.impl.javascript;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.hadoop.gateway.util.urltemplate.Resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class JavaScriptUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+  private static String[] TYPES = new String[]{ "application/javascritp", "text/javascript", "*/javascript",
+      "application/x-javascript", "text/x-javascript", "*/x-javascript" };
+  private static String[] NAMES = new String[]{ null };
+
+  @Override
+  public String[] getTypes() {
+    return TYPES;
+  }
+
+  @Override
+  public String[] getNames() {
+    return NAMES;
+  }
+
+  @Override
+  public InputStream filter(
+      InputStream stream,
+      String encoding,
+      UrlRewriter rewriter,
+      Resolver resolver,
+      UrlRewriter.Direction direction,
+      UrlRewriteFilterContentDescriptor config )
+          throws IOException {
+    if ( config != null ) {
+      return new ReaderInputStream(
+          new JavaScriptUrlRewriteFilterReader(
+              new InputStreamReader( stream, encoding ), rewriter, resolver, direction, config ) );
+    } else {
+      return stream;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter b/gateway-provider-rewrite/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter
index 2fb34b4..06d4eb6 100644
--- a/gateway-provider-rewrite/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter
+++ b/gateway-provider-rewrite/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteStreamFilter
@@ -20,4 +20,5 @@ org.apache.hadoop.gateway.filter.rewrite.impl.json.JsonUrlRewriteStreamFilter
 org.apache.hadoop.gateway.filter.rewrite.impl.xml.XmlUrlRewriteStreamFilter
 org.apache.hadoop.gateway.filter.rewrite.impl.html.HtmlUrlRewriteStreamFilter
 org.apache.hadoop.gateway.filter.rewrite.impl.form.FormUrlRewriteStreamFilter
-org.apache.hadoop.gateway.filter.rewrite.impl.noop.NoOpUrlRewriteStreamFilter
\ No newline at end of file
+org.apache.hadoop.gateway.filter.rewrite.impl.noop.NoOpUrlRewriteStreamFilter
+org.apache.hadoop.gateway.filter.rewrite.impl.javascript.JavaScriptUrlRewriteStreamFilter
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponseTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponseTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponseTest.java
index 1f20b87..3bd9e10 100644
--- a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponseTest.java
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteResponseTest.java
@@ -17,17 +17,28 @@
  */
 package org.apache.hadoop.gateway.filter.rewrite.impl;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteProcessor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteServletContextListener;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteServletFilter;
 import org.easymock.EasyMock;
 import org.junit.Test;
 
+import javax.activation.MimeTypeParseException;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.List;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -105,4 +116,56 @@ public class UrlRewriteResponseTest {
     assertThat( path, hasItems( new String[]{ "/mock-path" } ) );
   }
 
+  @Test
+  public void testStreamResponse() throws IOException, MimeTypeParseException {
+    UrlRewriteProcessor rewriter = EasyMock.createNiceMock( UrlRewriteProcessor.class );
+    EasyMock.expect( rewriter.getConfig() ).andReturn( null ).anyTimes();
+
+    ServletContext context = EasyMock.createNiceMock( ServletContext.class );
+    EasyMock.expect( context.getAttribute( UrlRewriteServletContextListener.PROCESSOR_ATTRIBUTE_NAME ) ).andReturn( rewriter ).anyTimes();
+
+    FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
+    EasyMock.expect( config.getInitParameter( UrlRewriteServletFilter.RESPONSE_BODY_FILTER_PARAM ) ).andReturn( "test-filter" ).anyTimes();
+    EasyMock.expect( config.getServletContext() ).andReturn( context ).anyTimes();
+
+    HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
+    HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
+
+    EasyMock.replay( rewriter, context, config, request, response );
+
+    UrlRewriteResponse rewriteResponse = new UrlRewriteResponse( config, request, response );
+
+    String content = "content to test gzip streaming";
+    testStreamResponseGzip ( content, rewriteResponse, false );
+    testStreamResponseGzip ( content, rewriteResponse, true );
+  }
+
+  private void testStreamResponseGzip( String content, UrlRewriteResponse rewriteResponse , boolean isGzip ) throws IOException {
+    File targetDir = new File( System.getProperty( "user.dir" ), "target" );
+    File inputFile = new File( targetDir, "input.test" );
+    File outputFile = new File( targetDir, "output.test" );
+    OutputStream outStream = null, output = null;
+    InputStream inStream = null, input = null;
+    try {
+      outStream = isGzip ? new GZIPOutputStream( new FileOutputStream( inputFile ) ) : new FileOutputStream( inputFile );
+      outStream.write( content.getBytes() );
+      outStream.close();
+
+      input = new FileInputStream( inputFile );
+      output = new FileOutputStream( outputFile );
+      rewriteResponse.streamResponse( input, output );
+
+      inStream = isGzip ? new GZIPInputStream( new FileInputStream( outputFile ) ) : new FileInputStream( outputFile );
+      assertThat( String.valueOf( IOUtils.toCharArray( inStream ) ), is( content ) );
+    } finally {
+      if ( inStream != null ) {
+        inStream.close();
+      }
+      if ( input != null ) {
+        input.close();
+      }
+      inputFile.delete();
+      outputFile.delete();
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBaseTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBaseTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBaseTest.java
index 6db5802..2150cca 100644
--- a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBaseTest.java
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/html/HtmlFilterReaderBaseTest.java
@@ -31,6 +31,7 @@ import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteCheckDescriptorExt
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteControlDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteMatchDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteMatchDescriptorExt;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFilterContentDescriptorImpl;
 import org.apache.hadoop.gateway.filter.rewrite.impl.xml.XmlRewriteRulesDigester;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteActionDescriptorBase;
 import org.hamcrest.Matchers;
@@ -56,6 +57,7 @@ import java.io.Writer;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import static org.hamcrest.CoreMatchers.hasItem;
 import static org.hamcrest.CoreMatchers.is;
@@ -83,6 +85,11 @@ public class HtmlFilterReaderBaseTest {
     protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
       return attributeValue;
     }
+
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      return value;
+    }
   }
 
   public static class MapXmlFilterReader extends HtmlFilterReaderBase {
@@ -102,6 +109,43 @@ public class HtmlFilterReaderBaseTest {
     protected String filterText( QName elementName, String text, String ruleName ) {
       return map.get( text.trim() );
     }
+
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      return map.get( value );
+    }
+  }
+
+  public static class MatchRuleXmlFilterReader extends HtmlFilterReaderBase {
+    private Map<String, Map<String,String>> rules;
+    public MatchRuleXmlFilterReader( Reader reader, Map<String, Map<String,String>> rules, UrlRewriteFilterContentDescriptor config ) throws IOException, ParserConfigurationException {
+      super( reader, config );
+      this.rules = rules;
+    }
+
+    @Override
+    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
+      return filterValueString( attributeName.getLocalPart(), attributeValue, ruleName );
+    }
+
+    @Override
+    protected String filterText( QName elementName, String text, String ruleName ) {
+      return filterValueString( elementName.getLocalPart(), text, ruleName );
+    }
+
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      Map<String, String> rule = rules.get( ruleName );
+      if ( rule == null ){
+        return value;
+      }
+      for ( Map.Entry<String, String> entry : rule.entrySet() ) {
+        if ( Pattern.compile( entry.getKey() ).matcher( value ).matches() ) {
+          return entry.getValue();
+        }
+      }
+      return value;
+    }
   }
 
   @Test
@@ -244,6 +288,49 @@ public class HtmlFilterReaderBaseTest {
     assertThat( the( outputXml ), hasXPath( "/n1:root/n2:child2/text()", ns, equalTo( "child2-output" ) ) );
   }
 
+  @Test
+  public void testSimpleJavaScriptText() throws IOException, ParserConfigurationException {
+    String inputXml = "<root><script type=\"text/javascript\">input-js-text</script></root>";
+    StringReader inputReader = new StringReader( inputXml );
+    HtmlFilterReaderBase filterReader = new NoopXmlFilterReader( inputReader );
+    String outputXml = new String( IOUtils.toCharArray( filterReader ) );
+    assertThat( the( outputXml ), hasXPath( "/root/script/text()", equalTo( "input-js-text" ) ) );
+  }
+
+  @Test
+  public void testMatchedJavaScriptText() throws IOException, ParserConfigurationException {
+    Map<String, Map<String, String>> rules = new HashMap<String, Map<String, String>>();
+    Map<String, String> map = new HashMap<String, String>();
+    map.put( "(https?://[^/':,]+:[\\d]+)?/cluster/app", "https://knoxhost:8443/cluster/app" );
+    rules.put( "test-rule", map );
+    String inputXml =
+        "<root>\n" +
+        "  <script type=\"text/javascript\">\n" +
+        "    var appsTableData=[\n" +
+        "      [\"<a href='/cluster/app/application_1436831599487_0008'>application_1436831599487_0008</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='http://testhost:8088/cluster/app/application_1436831599487_0008'>History</a>\"],\n" +
+        "      [\"<a href='/cluster/app/application_1436831599487_0006'>application_1436831599487_0006</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='http://testhost:8088/cluster/app/application_1436831599487_0006'>History</a>\"],\n" +
+        "      [\"<a href='/cluster/app/application_1436831599487_0007'>application_1436831599487_0007</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='http://testhost:8088/cluster/app/application_1436831599487_0007'>History</a>\"]\n" +
+        "    ]\n" +
+        "  </script>\n" +
+        "</root>\n";
+    StringReader inputReader = new StringReader( inputXml );
+    UrlRewriteFilterContentDescriptor config = new UrlRewriteFilterContentDescriptorImpl();
+    config.addApply( "(https?://[^/':,]+:[\\d]+)?/cluster/app", "test-rule" );
+    HtmlFilterReaderBase filterReader = new MatchRuleXmlFilterReader( inputReader, rules, config );
+    String outputXml = new String( IOUtils.toCharArray( filterReader ) );
+    String expectedOutput =
+        "<root>\n" +
+        "  <script type=\"text/javascript\">\n" +
+        "    var appsTableData=[\n" +
+        "      [\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0008'>application_1436831599487_0008</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0008'>History</a>\"],\n" +
+        "      [\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0006'>application_1436831599487_0006</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0006'>History</a>\"],\n" +
+        "      [\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0007'>application_1436831599487_0007</a>\",\"hdfs\",\"Spark Pi\",\"SPARK\",\"<a href='https://knoxhost:8443/cluster/app/application_1436831599487_0007'>History</a>\"]\n" +
+        "    ]\n" +
+        "  </script>\n" +
+        "</root>\n";
+    assertThat( outputXml, is( expectedOutput ) );
+  }
+
   public static class XmlRewriteRulesDescriptorDigesterTest {
 
     private static DigesterLoader loader = DigesterLoader.newLoader( new XmlRewriteRulesDigester() );
@@ -629,6 +716,10 @@ public class HtmlFilterReaderBaseTest {
       return "text:" + ruleName + "{" + text + "}";
     }
 
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      return value;
+    }
   }
 
   public void dump( Node node, Writer writer ) throws TransformerException {

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReaderTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReaderTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReaderTest.java
new file mode 100644
index 0000000..88362db
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReaderTest.java
@@ -0,0 +1,118 @@
+/**
+ * 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.filter.rewrite.impl.javascript;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFilterContentDescriptorImpl;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class JavaScriptFilterReaderTest {
+  public static class NoopJsFilterReader extends JavaScriptFilterReader {
+    public NoopJsFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
+      super( reader, config );
+    }
+
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      return value;
+    }
+  }
+
+  public static class MatchRuleJsFilterReader extends JavaScriptFilterReader {
+    private Map<String, Map<String,String>> rules;
+    public MatchRuleJsFilterReader( Reader reader, Map<String, Map<String,String>> rules, UrlRewriteFilterContentDescriptor config ) throws IOException {
+      super( reader, config );
+      this.rules = rules;
+    }
+
+    @Override
+    public String filterValueString( String name, String value, String ruleName ) {
+      Map<String, String> rule = rules.get( ruleName );
+      if ( rule == null ) {
+        return value;
+      }
+      for ( Map.Entry<String, String> entry : rule.entrySet() ) {
+        if ( Pattern.compile( entry.getKey() ).matcher( value ).matches() ) {
+          return entry.getValue();
+        }
+      }
+      return value;
+    }
+  }
+
+  @Test
+  public void testSimple() throws IOException {
+    String inputJs = "function load_page() {}\n";
+    StringReader inputReader = new StringReader( inputJs );
+    UrlRewriteFilterContentDescriptor config = new UrlRewriteFilterContentDescriptorImpl();
+    JavaScriptFilterReader filterReader = new NoopJsFilterReader( inputReader, config );
+    String outputJs = new String( IOUtils.toCharArray( filterReader ) );
+    assertThat( outputJs, is ( inputJs ) );
+  }
+
+  @Test
+  public void testSimpleMultipleLines() throws IOException {
+    String inputJs =
+        "var url = '/webhdfs/v1' + abs_path + '?op=GET_BLOCK_LOCATIONS';\n" +
+        "$.ajax({\"url\": url, \"crossDomain\": true}).done(function(data) {}).error(network_error_handler(url));\n";
+    StringReader inputReader = new StringReader( inputJs );
+    UrlRewriteFilterContentDescriptor config = new UrlRewriteFilterContentDescriptorImpl();
+    config.addApply( "/webhdfs/v1", "test-rule" );
+    JavaScriptFilterReader filterReader = new NoopJsFilterReader( inputReader, config );
+    String outputJs = new String( IOUtils.toCharArray( filterReader ) );
+    assertThat( outputJs, is ( inputJs ) );
+  }
+
+  @Test
+  public void testMatchedJsContent() throws IOException {
+    Map<String, Map<String, String>> rules = new HashMap<String, Map<String, String>>();
+    Map<String, String> map = new HashMap<String, String>();
+    map.put( "(https?://[^/':,]+:[\\d]+)?/cluster/app", "https://knoxhost:8443/cluster/app" );
+    map.put( "/webhdfs/v1", "https://knoxhost:8443/webhdfs/v1" );
+    rules.put( "test-rule", map );
+    String inputJs =
+        "var url = '/webhdfs/v1' + abs_path + '?op=GET_BLOCK_LOCATIONS';\n" +
+        "$.ajax({\"url\": url, \"crossDomain\": true}).done(function(data) {\n" +
+        "  var url = http://testhost:8088/cluster/app/application_1436831599487_0001;\n" +
+        "}).error(network_error_handler(url));\n";
+    StringReader inputReader = new StringReader( inputJs );
+    UrlRewriteFilterContentDescriptor config = new UrlRewriteFilterContentDescriptorImpl();
+    config.addApply( "(https?://[^/':,]+:[\\d]+)?/cluster/app", "test-rule" );
+    config.addApply( "/webhdfs/v1", "test-rule" );
+    JavaScriptFilterReader filterReader = new MatchRuleJsFilterReader( inputReader, rules, config );
+    String outputJs = new String( IOUtils.toCharArray( filterReader ) );
+    String expectedOutputJs =
+        "var url = 'https://knoxhost:8443/webhdfs/v1' + abs_path + '?op=GET_BLOCK_LOCATIONS';\n" +
+        "$.ajax({\"url\": url, \"crossDomain\": true}).done(function(data) {\n" +
+        "  var url = https://knoxhost:8443/cluster/app/application_1436831599487_0001;\n" +
+        "}).error(network_error_handler(url));\n";
+    assertThat( outputJs, is ( expectedOutputJs ) );
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/rewrite.xml b/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/rewrite.xml
new file mode 100644
index 0000000..8045811
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/rewrite.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<rules>
+
+  <rule dir="IN" name="HBASEUI/hbase/inbound/master/root" pattern="*://*:*/**/hbase/webui">
+    <rewrite template="{$serviceUrl[HBASEUI]}/master-status"/>
+  </rule>
+  <rule dir="IN" name="HBASEUI/hbase/inbound/master/path" pattern="*://*:*/**/hbase/webui/{**}">
+    <rewrite template="{$serviceUrl[HBASEUI]}/{**}"/>
+  </rule>
+  <rule dir="IN" name="HBASEUI/hbase/inbound/master/query" pattern="*://*:*/**/hbase/webui/{**}?{**}">
+    <rewrite template="{$serviceUrl[HBASEUI]}/{**}?{**}"/>
+  </rule>
+  <rule dir="IN" name="HBASEUI/hbase/inbound/regionserver/home" pattern="*://*:*/**/hbase/webui/regionserver/rs-status?{host}?{port}">
+    <rewrite template="{$serviceScheme[HBASEUI]}://{host}:{port}/rs-status"/>
+  </rule>
+  <rule dir="IN" name="HBASEUI/hbase/inbound/master/home" pattern="*://*:*/**/hbase/webui/master/master-status?{host}?{port}">
+    <rewrite template="{$serviceScheme[HBASEUI]}://{host}:{port}/master-status"/>
+  </rule>
+
+  <rule dir="IN" name="HBASEUI/hbase/inbound/logs" pattern="*://*:*/**/hbase/webui/logs?{scheme}?{host}?{port}?{**}">
+    <rewrite template="{scheme}://{host}:{port}/logs/?{**}"/>
+  </rule>
+
+  <filter name="HBASEUI/hbase/outbound/headers">
+    <content type="application/x-http-headers">
+      <apply path="Location" rule="HBASEUI/hbase/outbound/headers/location"/>
+    </content>
+  </filter>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/headers/location">
+    <match pattern="{scheme}://{host}:{port}/logs/?{**}"/>
+    <rewrite template="{$frontend[url]}/hbase/webui/logs?{scheme}?host={$hostmap(host)}?{port}?{**}"/>
+  </rule>
+
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/regionserver/home" pattern="//{host}:{port}/rs-status/">
+    <rewrite template="{$frontend[url]}/hbase/webui/regionserver/rs-status?host={$hostmap(host)}?{port}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/master/home" pattern="//{host}:{port}/master-status/">
+    <rewrite template="{$frontend[url]}/hbase/webui/master/master-status?host={$hostmap(host)}?{port}"/>
+  </rule>
+
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/png" pattern="/static/{hbase*.png}">
+    <rewrite template="{$frontend[url]}/hbase/webui/static/{hbase*.png}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/static" pattern="/static/{**}">
+    <rewrite template="{$frontend[url]}/hbase/webui/static/{**}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/master" pattern="/master-status">
+    <rewrite template="{$frontend[url]}/hbase/webui/master-status"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/tables" pattern="/tablesDetailed.jsp">
+    <rewrite template="{$frontend[url]}/hbase/webui/tablesDetailed.jsp"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/logs" pattern="/logs/">
+    <rewrite template="{$frontend[url]}/hbase/webui/logs/"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/logs/files" pattern="/logs/{**}">
+    <rewrite template="{$frontend[url]}/hbase/webui/logs/{**}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/logLevel" pattern="/logLevel">
+    <rewrite template="{$frontend[url]}/hbase/webui/logLevel"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/debug" pattern="/dump">
+    <rewrite template="{$frontend[url]}/hbase/webui/dump"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/jmx" pattern="/jmx">
+    <rewrite template="{$frontend[url]}/hbase/webui/jmx"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/conf" pattern="/conf">
+    <rewrite template="{$frontend[url]}/hbase/webui/conf"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/table" pattern="table.jsp?{**}">
+    <rewrite template="{$frontend[url]}/hbase/webui/table.jsp?{**}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/filter" pattern="?{filter}">
+    <rewrite template="{$frontend[url]}/hbase/webui/master-status?{filter}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/format" pattern="?{format}?{filter}">
+    <rewrite template="{$frontend[url]}/hbase/webui/master-status?{format}?{filter}"/>
+  </rule>
+  <rule dir="OUT" name="HBASEUI/hbase/outbound/zkdump" pattern="/zk.jsp">
+    <rewrite template="{$frontend[url]}/hbase/webui/zk.jsp"/>
+  </rule>
+
+  <filter name="HBASEUI/hbase/outbound/configuration">
+    <content type="*/xml">
+      <buffer path="/configuration/property"/>
+    </content>
+  </filter>
+</rules>

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/service.xml b/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/service.xml
new file mode 100644
index 0000000..98e17fe
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/hbaseui/1.1.0/service.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<service role="HBASEUI" name="hbase" version="1.1.0">
+    <routes>
+        <route path="/hbase/webui/">
+            <rewrite apply="HBASEUI/hbase/inbound/master/root" to="request.url"/>
+        </route>
+        <route path="/hbase/webui/**">
+            <rewrite apply="HBASEUI/hbase/inbound/master/path" to="request.url"/>
+            <rewrite apply="HBASEUI/hbase/outbound/headers" to="response.headers"/>
+        </route>
+        <route path="/hbase/webui/**?**">
+            <rewrite apply="HBASEUI/hbase/inbound/master/query" to="request.url"/>
+            <rewrite apply="HBASEUI/hbase/outbound/tasks" to="response.body"/>
+        </route>
+        <route path="/hbase/webui/regionserver/**?{host}?{port}">
+            <rewrite apply="HBASEUI/hbase/inbound/regionserver/home" to="request.url"/>
+        </route>
+        <route path="/hbase/webui/master/**?{host}?{port}">
+            <rewrite apply="HBASEUI/hbase/inbound/master/home" to="request.url"/>
+        </route>
+        <route path="/hbase/webui/logs?**">
+            <rewrite apply="HBASEUI/hbase/outbound/headers" to="response.headers"/>
+        </route>
+        <route path="/hbase/webui/conf">
+            <rewrite apply="HBASEUI/hbase/outbound/configuration" to="response.body"/>
+        </route>
+    </routes>
+    <dispatch classname="org.apache.hadoop.gateway.hbase.HBaseDispatch"/>
+</service>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/rewrite.xml b/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/rewrite.xml
new file mode 100644
index 0000000..3c88be4
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/rewrite.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<rules>
+
+  <rule dir="IN" name="HDFSUI/hdfs/inbound/namenode/root" pattern="*://*:*/**/hdfs/">
+    <rewrite template="{$serviceUrl[HDFSUI]}/dfshealth.html"/>
+  </rule>
+  <rule dir="IN" name="HDFSUI/hdfs/inbound/namenode/path" pattern="*://*:*/**/hdfs/{**}">
+    <rewrite template="{$serviceUrl[HDFSUI]}/{**}"/>
+  </rule>
+  <rule dir="IN" name="HDFSUI/hdfs/inbound/namenode/query" pattern="*://*:*/**/hdfs/{**}?{**}">
+    <rewrite template="{$serviceUrl[HDFSUI]}/{**}?{**}"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/bootstrapcss" pattern="/static/{bootstrap=bootstrap*}/css/{**}">
+    <rewrite template="{$frontend[url]}/hdfs/static/{bootstrap}/css/{**}"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/hadoopcss" pattern="/static/hadoop.css">
+    <rewrite template="{$frontend[url]}/hdfs/static/hadoop.css"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/jquery" pattern="/static/jquery-1.10.2.min.js">
+    <rewrite template="{$frontend[url]}/hdfs/static/jquery-1.10.2.min.js"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/dust" pattern="/static/{dust=*dust*js}">
+    <rewrite template="{$frontend[url]}/hdfs/static/{dust}"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/bootstrapjs" pattern="/static/{bootstrap=bootstrap*}/js/{**}">
+    <rewrite template="{$frontend[url]}/hdfs/static/{bootstrap}/js/{**}"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/logs" pattern="logs">
+    <rewrite template="{$frontend[url]}/hdfs/logs"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/logs/files" pattern="/logs/{**}">
+    <rewrite template="{$frontend[url]}/hdfs/logs/{**}"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/dfshealthjs" pattern="dfshealth.js">
+    <rewrite template="{$frontend[url]}/hdfs/dfshealth.js"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/explorerhtml" pattern="explorer.html">
+    <rewrite template="{$frontend[url]}/hdfs/explorer.html"/>
+  </rule>
+
+  <rule dir="IN" name="HDFSUI/hdfs/inbound/logs" pattern="*://*:*/**/hdfs/logs?{scheme}?{host}?{port}?{**}">
+    <rewrite template="{scheme}://{host}:{port}/logs/?{**}"/>
+  </rule>
+
+  <filter name="HDFSUI/hdfs/outbound/headers">
+    <content type="application/x-http-headers">
+      <apply path="Location" rule="HDFSUI/hdfs/outbound/headers/location"/>
+    </content>
+  </filter>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/headers/location">
+    <match pattern="{scheme}://{host}:{port}/logs/?{**}"/>
+    <rewrite template="{$frontend[url]}/hdfs/logs?{scheme}?host={$hostmap(host)}?{port}?{**}"/>
+  </rule>
+
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/namenode/dfs/jmx">
+    <rewrite template="{$frontend[url]}/hdfs/jmx"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/namenode/dfs/conf">
+    <rewrite template="{$frontend[url]}/hdfs/conf"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/namenode/dfs/startupProgress">
+    <rewrite template="{$frontend[url]}/hdfs/startupProgress"/>
+  </rule>
+  <rule dir="OUT" name="HDFSUI/hdfs/outbound/namenode/dfs/webhdfs">
+    <rewrite template="{$frontend[url]}/webhdfs"/>
+  </rule>
+  <filter name="HDFSUI/hdfs/outbound/namenode/dfs">
+    <content type="*/x-javascript">
+      <apply path="/jmx" rule="HDFSUI/hdfs/outbound/namenode/dfs/jmx"/>
+      <apply path="/conf" rule="HDFSUI/hdfs/outbound/namenode/dfs/conf"/>
+      <apply path="/startupProgress" rule="HDFSUI/hdfs/outbound/namenode/dfs/startupProgress"/>
+      <apply path="/webhdfs" rule="HDFSUI/hdfs/outbound/namenode/dfs/webhdfs"/>
+    </content>
+    <content type="*/html">
+    </content>
+  </filter>
+
+</rules>

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/service.xml b/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/service.xml
new file mode 100644
index 0000000..fb8e231
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/hdfsui/2.7.0/service.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<service role="HDFSUI" name="hdfs" version="2.7.0">
+    <routes>
+        <route path="/hdfs/">
+            <rewrite apply="HDFSUI/hdfs/inbound/namenode/root" to="request.url"/>
+            <rewrite apply="HDFSUI/hdfs/outbound/namenode/dfs" to="response.body"/>
+        </route>
+        <route path="/hdfs/**">
+            <rewrite apply="HDFSUI/hdfs/inbound/namenode/path" to="request.url"/>
+            <rewrite apply="HDFSUI/hdfs/outbound/headers" to="response.headers"/>
+            <rewrite apply="HDFSUI/hdfs/outbound/namenode/dfs" to="response.body"/>
+        </route>
+        <route path="/hdfs/**?**">
+            <rewrite apply="HDFSUI/hdfs/inbound/namenode/query" to="request.url"/>
+            <rewrite apply="HDFSUI/hdfs/outbound/namenode/dfs" to="response.body"/>
+        </route>
+        <route path="/hdfs/logs?**">
+            <rewrite apply="HDFSUI/hdfs/outbound/headers" to="response.headers"/>
+            <rewrite apply="HDFSUI/hdfs/outbound/namenode/dfs" to="response.body"/>
+        </route>
+    </routes>
+    <dispatch classname="org.apache.hadoop.gateway.hdfs.dispatch.HdfsHttpClientDispatch" ha-classname="org.apache.hadoop.gateway.hdfs.dispatch.WebHdfsHaDispatch"/>
+</service>

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/rewrite.xml b/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/rewrite.xml
new file mode 100644
index 0000000..69ce69e
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/rewrite.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<rules>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/root" pattern="*://*:*/**/jobhistory/">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/path" pattern="*://*:*/**/jobhistory/{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory/{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/query" pattern="*://*:*/**/jobhistory/{**}?{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory/{**}?{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/static" pattern="*://*:*/**/jobhistory/static/{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/static/{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/conf" pattern="*://*:*/**/jobhistory/conf">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/conf"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/logs" pattern="*://*:*/**/jobhistory/logs">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/logs"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/joblogs" pattern="*://*:*/**/jobhistory/joblogs">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory/logs"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/logs/files" pattern="*://*:*/**/jobhistory/logs/{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/logs/{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/joblogs/filecontent" pattern="*://*:*/**/jobhistory/joblogs/{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory/logs/{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/joblogs/fullfilecontent" pattern="*://*:*/**/jobhistory/joblogs/{**}/?{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jobhistory/logs/{**}/?{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/logs/redirect" pattern="*://*:*/**/jobhistory/logs?{scheme}?{host}?{port}?{**}">
+    <rewrite template="{scheme}://{host}:{port}/logs/?{**}"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/stacks" pattern="*://*:*/**/jobhistory/stacks">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/stacks"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/metrics" pattern="*://*:*/**/jobhistory/metrics">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/metrics"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/jmx" pattern="*://*:*/**/jobhistory/jmx">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jmx"/>
+  </rule>
+  <rule dir="IN" name="JOBHISTORYUI/jobhistory/inbound/jmx/query" pattern="*://*:*/**/jobhistory/jmx?{**}">
+    <rewrite template="{$serviceUrl[JOBHISTORYUI]}/jmx?{**}"/>
+  </rule>
+
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/headers/location">
+    <match pattern="{scheme}://{host}:{port}/logs/?{**}"/>
+    <rewrite template="{$frontend[url]}/jobhistory/logs?{scheme}?host={$hostmap(host)}?{port}?{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/logs/files" pattern="/logs/{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/logs/{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/static" pattern="/static/{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/static/{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobhistory" pattern="/jobhistory/{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobhistory/query" pattern="/jobhistory/{**}?{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/{**}?{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobhistory/logs" pattern="/jobhistory/logs/{**}/?{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/joblogs/{**}/?{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/conf" pattern="/conf">
+    <rewrite template="{$frontend[url]}/jobhistory/conf"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/logs" pattern="/logs">
+    <rewrite template="{$frontend[url]}/jobhistory/logs"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/stacks" pattern="/stacks">
+    <rewrite template="{$frontend[url]}/jobhistory/stacks"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/metrics" pattern="/metrics">
+    <rewrite template="{$frontend[url]}/jobhistory/metrics"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jmx" pattern="/jmx?{**}">
+    <rewrite template="{$frontend[url]}/jobhistory/jmx?{**}"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobs/job">
+    <rewrite template="{$frontend[url]}/jobhistory/job"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobs/task">
+    <rewrite template="{$frontend[url]}/jobhistory/task"/>
+  </rule>
+  <rule dir="OUT" name="JOBHISTORYUI/jobhistory/outbound/jobs/logs">
+    <rewrite template="{$frontend[url]}/jobhistory/joblogs"/>
+  </rule>
+  <filter name="JOBHISTORYUI/jobhistory/outbound/headers">
+    <content type="application/x-http-headers">
+      <apply path="Location" rule="JOBHISTORYUI/jobhistory/outbound/headers/location"/>
+    </content>
+  </filter>
+  <filter name="JOBHISTORYUI/jobhistory/outbound/configuration">
+    <content type="*/xml">
+      <buffer path="/configuration/property"/>
+    </content>
+  </filter>
+  <filter name="JOBHISTORYUI/jobhistory/outbound/jobs">
+    <content type="*/html">
+      <apply path="/jobhistory/job" rule="JOBHISTORYUI/jobhistory/outbound/jobs/job"/>
+      <apply path="/jobhistory/task" rule="JOBHISTORYUI/jobhistory/outbound/jobs/task"/>
+      <apply path="/jobhistory/logs" rule="JOBHISTORYUI/jobhistory/outbound/jobs/logs"/>
+    </content>
+  </filter>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/service.xml b/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/service.xml
new file mode 100644
index 0000000..4594c01
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/jobhistoryui/2.7.0/service.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<service role="JOBHISTORYUI" name="jobhistory" version="2.7.0">
+    <routes>
+        <route path="/jobhistory/">
+            <rewrite apply="JOBHISTORYUI/jobhistory/outbound/jobs" to="response.body"/>
+        </route>
+        <route path="/jobhistory/**">
+            <rewrite apply="JOBHISTORYUI/jobhistory/outbound/jobs" to="response.body"/>
+        </route>
+        <route path="/jobhistory/**?**">
+            <rewrite apply="JOBHISTORYUI/jobhistory/outbound/jobs" to="response.body"/>
+        </route>
+        <route path="/jobhistory/logs?**">
+            <rewrite apply="JOBHISTORYUI/jobhistory/outbound/headers" to="response.headers"/>
+        </route>
+        <route path="/jobhistory/conf">
+            <rewrite apply="JOBHISTORYUI/jobhistory/outbound/configuration" to="response.body"/>
+        </route>
+     </routes>
+</service>

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/rewrite.xml b/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/rewrite.xml
new file mode 100644
index 0000000..2198b4b
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/rewrite.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<rules>
+    <rule dir="IN" name="OOZIEUI/oozie/inbound/root" pattern="*://*:*/**/oozie/">
+        <rewrite template="{$serviceUrl[OOZIEUI]}/"/>
+    </rule>
+    <rule dir="IN" name="OOZIEUI/oozie/inbound/path" pattern="*://*:*/**/oozie/{**}">
+        <rewrite template="{$serviceUrl[OOZIEUI]}/{**}"/>
+    </rule>
+    <rule dir="IN" name="OOZIEUI/oozie/inbound/query" pattern="*://*:*/**/oozie/{**}?{**}">
+        <rewrite template="{$serviceUrl[OOZIEUI]}/{**}?{**}"/>
+    </rule>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/service.xml b/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/service.xml
new file mode 100644
index 0000000..370888d
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/oozieui/4.2.0/service.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<service role="OOZIEUI" name="oozie" version="4.2.0">
+    <routes>
+        <route path="/oozie/"/>
+        <route path="/oozie/**"/>
+        <route path="/oozie/**?**"/>
+    </routes>
+</service>

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/rewrite.xml b/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/rewrite.xml
new file mode 100644
index 0000000..4e7a375
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/rewrite.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<rules>
+  <rule dir="IN" name="SPARKHISTORYUI/sparkhistory/inbound/root" pattern="*://*:*/**/sparkhistory/">
+    <rewrite template="{$serviceUrl[SPARKHISTORYUI]}/"/>
+  </rule>
+  <rule dir="IN" name="SPARKHISTORYUI/sparkhistory/inbound/path" pattern="*://*:*/**/sparkhistory/{**}">
+    <rewrite template="{$serviceUrl[SPARKHISTORYUI]}/{**}"/>
+  </rule>
+  <rule dir="IN" name="SPARKHISTORYUI/sparkhistory/inbound/query" pattern="*://*:*/**/sparkhistory/{**}?{**}">
+    <rewrite template="{$serviceUrl[SPARKHISTORYUI]}/{**}?{**}"/>
+  </rule>
+  <rule dir="IN" name="SPARKHISTORYUI/sparkhistory/inbound/history" pattern="*://*:*/**/sparkhistory/history/{**}/?{**}">
+    <rewrite template="{$serviceUrl[SPARKHISTORYUI]}/history/{**}/?{**}"/>
+  </rule>
+  <rule dir="IN" name="SPARKHISTORYUI/sparkhistory/inbound/apps" pattern="*://*:*/**/sparkhistory/?{page}?{showIncomplete}">
+    <rewrite template="{$serviceUrl[SPARKHISTORYUI]}/?{page}?{showIncomplete}"/>
+  </rule>
+
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/history" pattern="/history/{**}">
+    <rewrite template="{$frontend[url]}/sparkhistory/history/{**}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/history/job" pattern="/history/{**}?{**}">
+    <rewrite template="{$frontend[url]}/sparkhistory/history/{**}?{**}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/bootstrap" pattern="/static/{bootstrap=bootstrap*}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{bootstrap}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/vis" pattern="/static/{vis=vis.min.*}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{vis}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/webui" pattern="/static/webui.css">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/webui.css"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/timeline" pattern="/static/{timeline=timeline-view*}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{timeline}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/sorttable" pattern="/static/sorttable.js">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/sorttable.js"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/jquery" pattern="/static/{jquery=jquery*.min.js}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{jquery}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/initialize" pattern="/static/initialize-tooltips.js">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/initialize-tooltips.js"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/table" pattern="/static/table.js">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/table.js"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/additional" pattern="/static/additional-metrics.js">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/additional-metrics.js"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/spark" pattern="/static/{spark=spark*}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{spark}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/d3" pattern="/static/{d3=*d3.min.js}">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/{d3}"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/static/graphlib" pattern="/static/graphlib-dot.min.js">
+    <rewrite template="{$frontend[url]}/sparkhistory/static/graphlib-dot.min.js"/>
+  </rule>
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/apps" pattern="/?{page}?{showIncomplete}">
+    <rewrite template="{$frontend[url]}/sparkhistory/?{page}?{showIncomplete}"/>
+  </rule>
+
+  <rule dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/headers/location">
+    <match pattern="*://*:*/history/{**}/?{**}"/>
+    <rewrite template="{$frontend[url]}/sparkhistory/history/{**}/?{**}"/>
+  </rule>
+  <rule flow="OR" dir="OUT" name="SPARKHISTORYUI/sparkhistory/outbound/headers/jobs/location">
+    <match pattern="*://*:*/history/{**}/jobs">
+      <rewrite template="{$frontend[url]}/sparkhistory/history/{**}/jobs"/>
+    </match>
+    <match pattern="*://*:*/history/{**}/jobs/">
+      <rewrite template="{$frontend[url]}/sparkhistory/history/{**}/jobs/"/>
+    </match>
+  </rule>
+
+  <filter name="SPARKHISTORYUI/sparkhistory/outbound/headers">
+    <content type="application/x-http-headers">
+      <apply path="Location" rule="SPARKHISTORYUI/sparkhistory/outbound/headers/location"/>
+    </content>
+  </filter>
+  <filter name="SPARKHISTORYUI/sparkhistory/outbound/headers/jobs">
+    <content type="application/x-http-headers">
+      <apply path="Location" rule="SPARKHISTORYUI/sparkhistory/outbound/headers/jobs/location"/>
+    </content>
+  </filter>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/be727f18/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/service.xml b/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/service.xml
new file mode 100644
index 0000000..3662cd5
--- /dev/null
+++ b/gateway-service-definitions/src/main/resources/services/sparkhistoryui/1.4.0/service.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   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.
+-->
+<service role="SPARKHISTORYUI" name="sparkhistory" version="1.4.0">
+    <routes>
+        <route path="/sparkhistory/"/>
+        <route path="/sparkhistory/**"/>
+        <route path="/sparkhistory/**?**"/>
+        <route path="/sparkhistory/history/**?**">
+            <rewrite apply="SPARKHISTORYUI/sparkhistory/outbound/headers" to="response.headers"/>
+        </route>
+        <route path="/sparkhistory/history/**/?**">
+            <rewrite apply="SPARKHISTORYUI/sparkhistory/outbound/headers/jobs" to="response.headers"/>
+        </route>
+        <route path="/sparkhistory/history/**/jobs/**?**">
+            <rewrite apply="SPARKHISTORYUI/sparkhistory/outbound/headers/jobs" to="response.headers"/>
+        </route>
+    </routes>
+</service>