You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/01 13:17:21 UTC
[23/64] [partial] knox git commit: KNOX-998 - Refactoring save 1
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormFilterReader.java
new file mode 100644
index 0000000..7d82633
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormFilterReader.java
@@ -0,0 +1,105 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteUtil;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+
+public class FormFilterReader extends Reader {
+
+ private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+ private int offset;
+ private StringWriter writer;
+ private StringBuffer buffer;
+ private Reader reader;
+ private FormReader parser;
+ private FormWriter generator;
+ private UrlRewriteFilterContentDescriptor config;
+
+ public FormFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
+ this.reader = reader;
+ this.config = config;
+ parser = new FormReader( reader );
+ writer = new StringWriter();
+ buffer = writer.getBuffer();
+ offset = 0;
+ generator = new FormWriter( writer );
+ }
+
+ @Override
+ public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
+ int count = 0;
+ int available = buffer.length() - offset;
+
+ if( available == 0 ) {
+ FormPair pair = parser.getNextPair();
+ if( pair == null ) {
+ count = -1;
+ } else {
+ processPair();
+ available = buffer.length() - offset;
+ }
+ }
+
+ 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;
+ }
+
+ private void processPair() throws IOException {
+ FormPair pair = parser.getCurrentPair();
+ String name = pair.getName();
+ String value = pair.getValue();
+ String rule = UrlRewriteUtil.pickFirstRuleWithEqualsIgnoreCasePathMatch( config, name );
+ try {
+ value = filterValue( name, pair.getValue(), rule );
+ pair.setValue( value );
+ } catch( Exception e ) {
+ LOG.failedToFilterValue( pair.getValue(), rule, e );
+ // Write original value.
+ }
+ generator.writePair( pair );
+ }
+
+ protected String filterValue( String name, String value, String rule ) {
+ return value;
+ }
+
+ @Override
+ public void close() throws IOException {
+ writer.close();
+ reader.close();
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormPair.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormPair.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormPair.java
new file mode 100644
index 0000000..95c896b
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormPair.java
@@ -0,0 +1,51 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+public class FormPair {
+
+ String name;
+ String value;
+
+ public FormPair() {
+ this.name = null;
+ this.value = null;
+ }
+
+ public FormPair( String name, String value ) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName( String name ) {
+ this.name = name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue( String value ) {
+ this.value = value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormReader.java
new file mode 100644
index 0000000..af34088
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormReader.java
@@ -0,0 +1,96 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+public class FormReader {
+
+ private static final String DEFFAULT_FORM_ENCODING = "UTF-8";
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024;
+
+ private Reader reader;
+ private FormPair current;
+ private StringBuilder buffer;
+ private int sepIndex;
+
+ public FormReader( Reader reader ) {
+ this.reader = reader;
+ this.current = null;
+ this.buffer = new StringBuilder( DEFAULT_BUFFER_SIZE );
+ this.sepIndex = -1;
+ }
+
+ public FormPair getNextPair() throws IOException {
+ while( true ) {
+ int c = reader.read();
+ switch( c ) {
+ case '=':
+ sepIndex = buffer.length();
+ break;
+ case '&':
+ // Ignore adjacent &s.
+ if( buffer.length() == 0 ) {
+ sepIndex = -1;
+ continue;
+ } else {
+ return createCurrentPair();
+ }
+ case -1:
+ // Ignore adjacent &s.
+ if( buffer.length() == 0 ) {
+ sepIndex = -1;
+ return null;
+ } else {
+ return createCurrentPair();
+ }
+ default:
+ buffer.append( (char)c );
+ break;
+ }
+ }
+ }
+
+ private FormPair createCurrentPair() throws UnsupportedEncodingException {
+ String name;
+ String value;
+ if( sepIndex >= 0 ) {
+ name = buffer.substring( 0, sepIndex );
+ value = buffer.substring( sepIndex );
+ } else {
+ name = buffer.toString();
+ value = "";
+ }
+ name = URLDecoder.decode( name, DEFFAULT_FORM_ENCODING );
+ value = URLDecoder.decode( value, DEFFAULT_FORM_ENCODING );
+ FormPair pair = new FormPair( name, value );
+ current = pair;
+ buffer.setLength( 0 );
+ sepIndex = -1;
+ return pair;
+ }
+
+ public FormPair getCurrentPair() {
+ return current;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteFilterReader.java
new file mode 100644
index 0000000..d8f8ba4
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteFilterReader.java
@@ -0,0 +1,60 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.urltemplate.Parser;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+import org.apache.knox.gateway.util.urltemplate.Template;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+public class FormUrlRewriteFilterReader extends FormFilterReader {
+
+ private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+ private Resolver resolver;
+ private UrlRewriter rewriter;
+ private UrlRewriter.Direction direction;
+
+ public FormUrlRewriteFilterReader( 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;
+ }
+
+ //TODO: Need to limit which values are attempted to be filtered by the name.
+ @Override
+ protected String filterValue( String name, String value, String rule ) {
+ try {
+ Template input = Parser.parseLiteral( value );
+ Template output = rewriter.rewrite( resolver, input, direction, rule );
+ value = output.getPattern();
+ } catch( URISyntaxException e ) {
+ LOG.failedToParseValueForUrlRewrite( value );
+ }
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..d75868d
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormUrlRewriteStreamFilter.java
@@ -0,0 +1,59 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class FormUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+ private static String[] TYPES = new String[]{ "application/x-www-form-urlencoded", "*/x-www-form-urlencoded" };
+ 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 {
+ return new ReaderInputStream(
+ new FormUrlRewriteFilterReader(
+ new InputStreamReader( stream, encoding ), rewriter, resolver, direction, config ), encoding );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormWriter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormWriter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormWriter.java
new file mode 100644
index 0000000..b59d4d4
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/form/FormWriter.java
@@ -0,0 +1,47 @@
+/**
+ * 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.filter.rewrite.impl.form;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URLEncoder;
+
+public class FormWriter {
+
+ private static final String DEFFAULT_FORM_ENCODING = "UTF-8";
+
+ private Writer writer;
+ boolean first;
+
+ public FormWriter( Writer writer ) {
+ this.writer = writer;
+ this.first = true;
+ }
+
+ public void writePair( FormPair pair ) throws IOException {
+ if( first ) {
+ first = false;
+ } else {
+ writer.write( "&" );
+ }
+ writer.write( URLEncoder.encode( pair.getName(), DEFFAULT_FORM_ENCODING ) );
+ writer.write( "=" );
+ writer.write( URLEncoder.encode( pair.getValue(), DEFFAULT_FORM_ENCODING ) );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
new file mode 100644
index 0000000..c141fa6
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReader.java
@@ -0,0 +1,61 @@
+/**
+ * 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.filter.rewrite.impl.html;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+
+import java.io.IOException;
+import java.io.Reader;
+
+//map.put( "meta", buildTagPattern( ".*url\\s*=\\s*['\"]?(.*?)[;\\s'\"\\/>].*" ) );
+//map.put( "link", buildTagPattern( ".*href\\s*=\\s*['\"]?(.*?)['\"\\>].*" ) );
+//map.put( "a", buildTagPattern( ".*href\\s*=\\s*['\"]?(.*?)['\"\\>].*" ) );
+//map.put( "th", buildTagPattern( ".*window.document.location\\s*=\\s*['\"]?(.*?)['\"\\>].*" ) );
+// assertMatch( pattern, "<meta HTTP-EQUIV=\"REFRESH\" content=\"0;url=dfshealth.jsp\"/>", "meta" );
+//String markup = "<link href=\"/static/org.apache.hadoop.css\" rel=\"stylesheet\" type=\"text/css\" >";
+//String markup = "<a href=\"dfsnodelist.jsp?whatNodes=DECOMMISSIONING\">";
+//String markup = "th class=headerASC onClick=\"window.document.location='/dfsnodelist.jsp?whatNodes=LIVE&sorter/field=name&sorter/order=DSC'\" title=\"sort on this column\">";
+
+public abstract class HtmlFilterReader extends HtmlFilterReaderBase {
+
+ public HtmlFilterReader( Reader reader ) throws IOException, ParserConfigurationException {
+ 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 );
+
+ @Override
+ protected final String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
+ return filterAttribute( elementName.getLocalPart(), attributeName.getLocalPart(), attributeValue, ruleName );
+ }
+
+ @Override
+ protected final String filterText( QName elementName, String text, String ruleName ) {
+ return filterText( elementName.getLocalPart(), text, ruleName );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
new file mode 100644
index 0000000..b90771b
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlFilterReaderBase.java
@@ -0,0 +1,327 @@
+/**
+ * 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.filter.rewrite.impl.html;
+
+import net.htmlparser.jericho.Attribute;
+import net.htmlparser.jericho.Attributes;
+import net.htmlparser.jericho.EndTag;
+import net.htmlparser.jericho.Segment;
+import net.htmlparser.jericho.StartTag;
+import net.htmlparser.jericho.StreamedSource;
+import net.htmlparser.jericho.Tag;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterReader;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteUtil;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class HtmlFilterReaderBase extends Reader implements
+ UrlRewriteFilterReader {
+
+ 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 );
+
+ private Document document;
+ private Stack<Level> stack;
+ private Reader reader;
+ private StreamedSource parser;
+ private Iterator<Segment> iterator;
+ private int lastSegEnd;
+ private int offset;
+ private StringWriter writer;
+ private StringBuffer buffer;
+ private UrlRewriteFilterContentDescriptor config = null;
+
+ protected HtmlFilterReaderBase( Reader reader ) throws IOException, ParserConfigurationException {
+ this.reader = reader;
+ document = XmlUtils.createDocument( false );
+ stack = new Stack<Level>();
+ parser = new StreamedSource( reader );
+ iterator = parser.iterator();
+ writer = new StringWriter();
+ buffer = writer.getBuffer();
+ 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 );
+
+ @Override
+ public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
+ int count = 0;
+ int available = buffer.length() - offset;
+
+ if( available == 0 ) {
+ if( iterator.hasNext() ) {
+ iterator.next();
+ processCurrentSegment();
+ 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;
+ }
+
+ private void processCurrentSegment() {
+ Segment segment = parser.getCurrentSegment();
+ // If this tag is inside the previous tag (e.g. a server tag) then
+ // ignore it as it was already output along with the previous tag.
+ if( segment.getEnd() <= lastSegEnd ) {
+ return;
+ }
+ lastSegEnd = segment.getEnd();
+ if( segment instanceof Tag ) {
+ if( segment instanceof StartTag ) {
+ processStartTag( (StartTag)segment );
+ } else if ( segment instanceof EndTag ) {
+ processEndTag( (EndTag)segment );
+ } else {
+ writer.write( segment.toString() );
+ }
+ } else {
+ processText( segment );
+ }
+ }
+
+ private void processEndTag( EndTag tag ) {
+ while( !stack.isEmpty() ) {
+ Level popped = stack.pop();
+ if( popped.getTag().getName().equalsIgnoreCase( tag.getName() ) ) {
+ break;
+ }
+ }
+ writer.write( tag.toString() );
+ }
+
+ private void processStartTag( StartTag tag ) {
+ if( "<".equals( tag.getTagType().getStartDelimiter() ) ) {
+ Element e = document.createElement( tag.getNameSegment().toString() );
+ stack.push( new Level( tag ) );
+ writer.write( "<" );
+ writer.write( tag.getNameSegment().toString() );
+ Attributes attributes = tag.getAttributes();
+ if( !attributes.isEmpty() ) {
+ for( Attribute attribute : attributes ) {
+ processAttribute( attribute );
+ }
+ }
+ if( tag.toString().trim().endsWith( "/>" ) || tag.isEmptyElementTag() ) {
+ stack.pop();
+ writer.write( "/>" );
+ } else {
+ writer.write( ">" );
+ }
+ } else {
+ writer.write( tag.toString() );
+ }
+ }
+
+ private void processAttribute( Attribute attribute ) {
+ writer.write( " " );
+ writer.write( attribute.getName() );
+ if(attribute.hasValue()) {
+ /*
+ * non decoded value, return the raw value of the attribute as it appears
+ * in the source document, without decoding, see KNOX-791.
+ */
+ String inputValue = attribute.getValueSegment().toString();
+ String outputValue = inputValue;
+ try {
+ Level tag = stack.peek();
+ String name = getRuleName(inputValue);
+ outputValue = filterAttribute( tag.getQName(), tag.getQName( attribute.getName() ), inputValue, name );
+ if( outputValue == null ) {
+ outputValue = inputValue;
+ }
+ } catch ( Exception e ) {
+ LOG.failedToFilterAttribute( attribute.getName(), e );
+ }
+ writer.write( "=" );
+ writer.write( attribute.getQuoteChar() );
+ writer.write( outputValue );
+ writer.write( attribute.getQuoteChar() );
+ }
+ }
+
+ private String getRuleName(String inputValue) {
+ if( config != null && !config.getSelectors().isEmpty() ) {
+ for( UrlRewriteFilterPathDescriptor selector : config.getSelectors() ) {
+ if ( selector instanceof UrlRewriteFilterApplyDescriptor) {
+ UrlRewriteFilterApplyDescriptor apply = (UrlRewriteFilterApplyDescriptor)selector;
+ Matcher matcher = apply.compiledPath( REGEX_COMPILER ).matcher( inputValue );
+ if (matcher.matches()) {
+ return apply.rule();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void processText( Segment segment ) {
+ String inputValue = segment.toString();
+ String outputValue = inputValue;
+ try {
+ if( stack.isEmpty() ) {
+ // This can happen for whitespace outside of the root element.
+ //outputValue = filterText( null, inputValue );
+ } else {
+ String tagName = stack.peek().getTag().getName();
+ if (SCRIPTTAG.equals(tagName) && config != null && !config.getSelectors().isEmpty() ) {
+ // embedded javascript content
+ outputValue = UrlRewriteUtil.filterJavaScript( inputValue, config, this, REGEX_COMPILER );
+ } else {
+ outputValue = filterText( stack.peek().getQName(), inputValue, getRuleName(inputValue) );
+ }
+ }
+ if( outputValue == null ) {
+ outputValue = inputValue;
+ }
+ } catch ( Exception e ) {
+ LOG.failedToFilterValue( inputValue, null, e );
+ }
+ writer.write( outputValue );
+ }
+
+ @Override
+ public void close() throws IOException {
+ parser.close();
+ reader.close();
+ writer.close();
+ stack.clear();
+ }
+
+ private String getNamespace( String prefix ) {
+ String namespace = null;
+ for( Level level : stack ) {
+ namespace = level.getNamespace( prefix );
+ if( namespace != null ) {
+ break;
+ }
+ }
+ return namespace;
+ }
+
+ private static class Level {
+ private StartTag tag;
+ private QName name;
+ private Map<String,String> namespaces;
+
+ private Level( StartTag tag ) {
+ this.tag = tag;
+ this.name = null;
+ this.namespaces = null;
+ }
+
+ private StartTag getTag() {
+ return tag;
+ }
+
+ private QName getQName() {
+ if( name == null ) {
+ name = getQName( tag.getName() );
+ }
+ return name;
+ }
+
+ private String getNamespace( String prefix ) {
+ return getNamespaces().get( prefix );
+ }
+
+ private QName getQName( String name ) {
+ String prefix;
+ String local;
+ int colon = ( name == null ? -1 : name.indexOf( ':' ) );
+ if( colon < 0 ) {
+ prefix = "";
+ local = name;
+ } else {
+ prefix = name.substring( 0, colon );
+ local = ( colon + 1 < name.length() ? name.substring( colon + 1 ) : "" );
+ }
+ String namespace = getNamespace( prefix );
+ return new QName( namespace, local, prefix );
+ }
+
+ private Map<String,String> getNamespaces() {
+ if( namespaces == null ) {
+ namespaces = new HashMap<>();
+ parseNamespaces();
+ }
+ return namespaces;
+ }
+
+ private void parseNamespaces() {
+ Attributes attributes = tag.getAttributes();
+ if( attributes != null ) {
+ for( Attribute attribute : tag.getAttributes() ) {
+ String name = attribute.getName();
+ if( name.toLowerCase().startsWith( "xmlns" ) ) {
+ int colon = name.indexOf( ":", 5 );
+ String prefix;
+ if( colon <= 0 ) {
+ prefix = "";
+ } else {
+ prefix = name.substring( colon );
+ }
+ namespaces.put( prefix, attribute.getValue() );
+ }
+ }
+ }
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionDescriptor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionDescriptor.java
new file mode 100644
index 0000000..ee11b7f
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionDescriptor.java
@@ -0,0 +1,31 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.filter.rewrite.impl.html;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public class HtmlImportFunctionDescriptor implements
+ UrlRewriteFunctionDescriptor<HtmlImportFunctionDescriptor> {
+
+ public static final String FUNCTION_NAME = "import";
+
+ @Override
+ public String name() {
+ return FUNCTION_NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
new file mode 100644
index 0000000..280f1b5
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
@@ -0,0 +1,90 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.filter.rewrite.impl.html;
+
+import org.apache.knox.gateway.filter.rewrite.api.FrontendFunctionDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFunctionProcessorFactory;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This function enhances the 'frontend' function with the ability to add a prefix to the rewritten frontend portion
+ * along with the '@import' literal. This is a workaround for the requirement to provide the ability to rewrite
+ * a portion of html content that contains a tag like the following
+ *
+ * <head> <style type=\"text/css\">@import "pretty.css";</style></head>
+ *
+ * and needs to be rewritten to something like
+ *
+ * <head> <style type=\"text/css\">@import "http://localhost:8443/sandbox/service/pretty.css";</style></head>
+ *
+ * The rewrite rule could then contain the $import function that would delegate to the frontend function.
+ *
+ * If there are more than one params passed, the first one is used as a prefix to the value of the frontend function.
+ *
+ */
+public class HtmlImportFunctionProcessor implements UrlRewriteFunctionProcessor<HtmlImportFunctionDescriptor> {
+
+ private static final String IMPORT_LITERAL = "@import";
+
+ private UrlRewriteFunctionProcessor frontend;
+
+ @Override
+ public void initialize(UrlRewriteEnvironment environment, HtmlImportFunctionDescriptor descriptor) throws Exception {
+ UrlRewriteFunctionDescriptor frontendDescriptor = UrlRewriteFunctionDescriptorFactory
+ .create(FrontendFunctionDescriptor.FUNCTION_NAME);
+ frontend = UrlRewriteFunctionProcessorFactory.create(FrontendFunctionDescriptor.FUNCTION_NAME, frontendDescriptor);
+ frontend.initialize(environment, frontendDescriptor);
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ frontend.destroy();
+ }
+
+ @Override
+ public List<String> resolve(UrlRewriteContext context, List<String> parameters) throws Exception {
+ String prefix = "";
+ if ( parameters != null && parameters.size() > 1 ) {
+ prefix = parameters.get(0);
+ parameters = parameters.subList(1, parameters.size());
+ }
+ List<String> frontendValues = frontend.resolve(context, parameters);
+ StringBuffer buffer = new StringBuffer(IMPORT_LITERAL);
+ buffer.append(" ");
+ buffer.append(prefix);
+ if ( frontendValues != null && frontendValues.size() > 0 ) {
+ for ( String value : frontendValues ) {
+ buffer.append(value);
+ }
+ }
+ return Arrays.asList(buffer.toString());
+ }
+
+ @Override
+ public String name() {
+ return HtmlImportFunctionDescriptor.FUNCTION_NAME;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixDescriptor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixDescriptor.java
new file mode 100644
index 0000000..0f37b50
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixDescriptor.java
@@ -0,0 +1,48 @@
+package org.apache.knox.gateway.filter.rewrite.impl.html;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+
+/**
+ * {@link UrlRewriteFunctionDescriptor} for the variable {@link
+ * HtmlPrefixDescriptor#FUNCTION_NAME}
+ *
+ * @since 0.14.0
+ */
+public class HtmlPrefixDescriptor
+ implements UrlRewriteFunctionDescriptor<HtmlPrefixDescriptor> {
+
+ /**
+ * variable name used in rewrite.xml
+ */
+ public static final String FUNCTION_NAME = "prefix";
+
+ /**
+ * Create an instance
+ */
+ public HtmlPrefixDescriptor() {
+ super();
+ }
+
+ @Override
+ public String name() {
+ return FUNCTION_NAME;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
new file mode 100644
index 0000000..d7983ef
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
@@ -0,0 +1,104 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.filter.rewrite.impl.html;
+
+import org.apache.knox.gateway.filter.rewrite.api.FrontendFunctionDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFunctionProcessorFactory;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This function enhances the 'frontend' function with the ability to add a
+ * prefix to the rewritten frontend portion along with the literals
+ * provided as an argument.
+ * <p>
+ * <div ng-include src=\"'components/navbar/navbar.html?v=1498928142479'\"></div>
+ * <p>
+ * and needs to be rewritten to something like
+ * <p>
+ * <div ng-include src=\"'http://localhost:8443/sandbox/service/components/navbar/navbar.html?v=1498928142479'\"></div>
+ * <p>
+ * The rewrite rule could then contain the $prefix function that would delegate
+ * to the frontend function.
+ * <p>
+ * The parameter to the function would be the symbol used as a prefix.
+ */
+
+public class HtmlPrefixProcessor
+ implements UrlRewriteFunctionProcessor<HtmlPrefixDescriptor> {
+
+ private UrlRewriteFunctionProcessor frontend;
+
+ /**
+ * Create an instance
+ */
+ public HtmlPrefixProcessor() {
+ super();
+ }
+
+ @Override
+ public void initialize(final UrlRewriteEnvironment environment,
+ final HtmlPrefixDescriptor descriptor) throws Exception {
+
+ final UrlRewriteFunctionDescriptor frontendDescriptor = UrlRewriteFunctionDescriptorFactory
+ .create(FrontendFunctionDescriptor.FUNCTION_NAME);
+
+ frontend = UrlRewriteFunctionProcessorFactory
+ .create(FrontendFunctionDescriptor.FUNCTION_NAME, frontendDescriptor);
+
+ frontend.initialize(environment, frontendDescriptor);
+ }
+
+ @Override
+ public String name() {
+ return HtmlPrefixDescriptor.FUNCTION_NAME;
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ frontend.destroy();
+ }
+
+ @Override
+ public List<String> resolve(UrlRewriteContext context,
+ List<String> parameters) throws Exception {
+ String prefix = "";
+
+ if ((parameters != null) && (parameters.size() > 1)) {
+ prefix = parameters.get(0);
+ parameters = parameters.subList(1, parameters.size());
+ }
+
+ final List<String> frontendValues = frontend.resolve(context, parameters);
+
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append(prefix);
+ if (frontendValues != null && frontendValues.size() > 0) {
+ for (final String value : frontendValues) {
+ buffer.append(value);
+ }
+ }
+
+ return Arrays.asList(buffer.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
new file mode 100644
index 0000000..faade4f
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteFilterReader.java
@@ -0,0 +1,74 @@
+/**
+ * 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.filter.rewrite.impl.html;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.urltemplate.Parser;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+import org.apache.knox.gateway.util.urltemplate.Template;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+public class HtmlUrlRewriteFilterReader extends HtmlFilterReader {
+
+ private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+ private Resolver resolver;
+ private UrlRewriter rewriter;
+ private UrlRewriter.Direction direction;
+
+ public HtmlUrlRewriteFilterReader( Reader reader, UrlRewriter rewriter, Resolver resolver, UrlRewriter.Direction direction, UrlRewriteFilterContentDescriptor config )
+ throws IOException, ParserConfigurationException {
+ 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.
+ @Override
+ public String filterValueString( String name, String value, String rule ) {
+ try {
+ Template input = Parser.parseLiteral( value );
+ Template output = rewriter.rewrite( resolver, input, direction, rule );
+ if( output != null ) {
+ value = output.getPattern();
+ }
+ } catch( URISyntaxException e ) {
+ LOG.failedToParseValueForUrlRewrite( value );
+ }
+ return value;
+ }
+
+ @Override
+ protected String filterAttribute( String tagName, String attributeName, String attributeValue, String ruleName ) {
+ return filterValueString( attributeName, attributeValue, ruleName );
+ }
+
+ @Override
+ protected String filterText( String tagName, String text, String ruleName ) {
+ return filterValueString( tagName, text, ruleName );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..543c323
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlUrlRewriteStreamFilter.java
@@ -0,0 +1,64 @@
+/**
+ * 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.filter.rewrite.impl.html;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class HtmlUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+ private static String[] TYPES = new String[]{ "application/html", "text/html", "*/html" };
+ 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 {
+ try {
+ return new ReaderInputStream(
+ new HtmlUrlRewriteFilterReader(
+ new InputStreamReader( stream, encoding ), rewriter, resolver, direction, config ), encoding );
+ } catch( ParserConfigurationException e ) {
+ throw new IOException( e );
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptFilterReader.java
new file mode 100644
index 0000000..89c5eaf
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/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.knox.gateway.filter.rewrite.impl.javascript;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterReader;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteUtil;
+import org.apache.knox.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/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteFilterReader.java
new file mode 100644
index 0000000..da1963b
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/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.knox.gateway.filter.rewrite.impl.javascript;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.urltemplate.Parser;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+import org.apache.knox.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.parseLiteral( 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/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..b93d6d3
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/javascript/JavaScriptUrlRewriteStreamFilter.java
@@ -0,0 +1,65 @@
+/**
+ * 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.filter.rewrite.impl.javascript;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.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/javascript", "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 ), encoding );
+ } else {
+ return stream;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
new file mode 100644
index 0000000..8286dbc
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
@@ -0,0 +1,644 @@
+/**
+ * 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.filter.rewrite.impl.json;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterBufferDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDetectDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterGroupDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.JsonPath;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+class JsonFilterReader extends Reader {
+
+ private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+ private static final UrlRewriteFilterPathDescriptor.Compiler<JsonPath.Expression> JPATH_COMPILER = new JsonPathCompiler();
+ private static final UrlRewriteFilterPathDescriptor.Compiler<Pattern> REGEX_COMPILER = new RegexCompiler();
+
+ private JsonFactory factory;
+ private JsonParser parser;
+ private JsonGenerator generator;
+ private ObjectMapper mapper;
+
+ private Reader reader;
+ private int offset;
+ private StringWriter writer;
+ private StringBuffer buffer;
+ private Stack<Level> stack;
+ private Level bufferingLevel;
+ private UrlRewriteFilterBufferDescriptor bufferingConfig;
+ private UrlRewriteFilterGroupDescriptor config;
+
+
+ public JsonFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
+ this.reader = reader;
+ factory = new JsonFactory();
+ mapper = new ObjectMapper();
+ parser = factory.createParser( reader );
+ writer = new StringWriter();
+ buffer = writer.getBuffer();
+ offset = 0;
+ generator = factory.createGenerator( writer );
+ stack = new Stack<Level>();
+ bufferingLevel = null;
+ bufferingConfig = null;
+ this.config = config;
+ }
+
+ @Override
+ public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
+ int count = 0;
+ int available = buffer.length() - offset;
+
+ if( available == 0 ) {
+ JsonToken token = parser.nextToken();
+ if( token == null ) {
+ count = -1;
+ } else {
+ processCurrentToken();
+ available = buffer.length() - offset;
+ }
+ }
+
+ 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;
+ }
+
+ private void processCurrentToken() throws IOException {
+ switch( parser.getCurrentToken() ) {
+ case START_OBJECT:
+ processStartObject();
+ break;
+ case END_OBJECT:
+ processEndObject();
+ break;
+ case START_ARRAY:
+ processStartArray();
+ break;
+ case END_ARRAY:
+ processEndArray();
+ break;
+ case FIELD_NAME:
+ processFieldName(); // Could be the name of an object, array or value.
+ break;
+ case VALUE_STRING:
+ processValueString();
+ break;
+ case VALUE_NUMBER_INT:
+ case VALUE_NUMBER_FLOAT:
+ processValueNumber();
+ break;
+ case VALUE_TRUE:
+ case VALUE_FALSE:
+ processValueBoolean();
+ break;
+ case VALUE_NULL:
+ processValueNull();
+ break;
+ case NOT_AVAILABLE:
+ // Ignore it.
+ break;
+ }
+ generator.flush();
+ }
+
+ private Level pushLevel( String field, JsonNode node, JsonNode scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
+ if( !stack.isEmpty() ) {
+ Level top = stack.peek();
+ if( scopeNode == null ) {
+ scopeNode = top.scopeNode;
+ scopeConfig = top.scopeConfig;
+ }
+ }
+ Level level = new Level( field, node, scopeNode, scopeConfig );
+ stack.push( level );
+ return level;
+ }
+
+ private void processStartObject() throws IOException {
+ JsonNode node;
+ Level child;
+ Level parent;
+ if( stack.isEmpty() ) {
+ node = mapper.createObjectNode();
+ child = pushLevel( null, node, node, config );
+ } else {
+ child = stack.peek();
+ if( child.node == null ) {
+ child.node = mapper.createObjectNode();
+ parent = stack.get( stack.size()-2 );
+ switch( parent.node.asToken() ) {
+ case START_ARRAY:
+ ((ArrayNode)parent.node ).add( child.node );
+ break;
+ case START_OBJECT:
+ ((ObjectNode)parent.node ).put( child.field, child.node );
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ } else if( child.isArray() ) {
+ parent = child;
+ node = mapper.createObjectNode();
+ child = pushLevel( null, node, null, null );
+ ((ArrayNode)parent.node ).add( child.node );
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+ if( bufferingLevel == null ) {
+ if( !startBuffering( child ) ) {
+ generator.writeStartObject();
+ }
+ }
+ }
+
+ private void processEndObject() throws IOException {
+ Level child;
+ Level parent;
+ child = stack.pop();
+ if( bufferingLevel == child ) {
+ filterBufferedNode( child );
+ mapper.writeTree( generator, child.node );
+ bufferingLevel = null;
+ bufferingConfig = null;
+ } else if( bufferingLevel == null ) {
+ generator.writeEndObject();
+ if( !stack.isEmpty() ) {
+ parent = stack.peek();
+ switch( parent.node.asToken() ) {
+ case START_ARRAY:
+ ((ArrayNode)parent.node ).removeAll();
+ break;
+ case START_OBJECT:
+ ((ObjectNode)parent.node ).removeAll();
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+
+ private void processStartArray() throws IOException {
+ JsonNode node;
+ Level child;
+ Level parent;
+ if( stack.isEmpty() ) {
+ node = mapper.createArrayNode();
+ child = pushLevel( null, node, node, config );
+ } else {
+ child = stack.peek();
+ if( child.node == null ) {
+ child.node = mapper.createArrayNode();
+ parent = stack.get( stack.size() - 2 );
+ switch( parent.node.asToken() ) {
+ case START_ARRAY:
+ ((ArrayNode)parent.node ).add( child.node );
+ break;
+ case START_OBJECT:
+ ((ObjectNode)parent.node ).put( child.field, child.node );
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ } else if( child.isArray() ) {
+ parent = child;
+ child = pushLevel( null, mapper.createArrayNode(), null, null );
+ ((ArrayNode)parent.node ).add( child.node );
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+ if( bufferingLevel == null ) {
+ if( !startBuffering( child ) ) {
+ generator.writeStartArray();
+ }
+ }
+ }
+
+ private void processEndArray() throws IOException {
+ Level child;
+ Level parent;
+ child = stack.pop();
+ if( bufferingLevel == child ) {
+ filterBufferedNode( child );
+ mapper.writeTree( generator, child.node );
+ bufferingLevel = null;
+ bufferingConfig = null;
+ } else if( bufferingLevel == null ) {
+ generator.writeEndArray();
+ if( !stack.isEmpty() ) {
+ parent = stack.peek();
+ switch( parent.node.asToken() ) {
+ case START_ARRAY:
+ ((ArrayNode)parent.node ).removeAll();
+ break;
+ case START_OBJECT:
+ ((ObjectNode)parent.node ).removeAll();
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+
+ private void processFieldName() throws IOException {
+ Level child = pushLevel( parser.getCurrentName(), null, null, null );
+ try {
+ child.field = filterFieldName( child.field );
+ } catch( Exception e ) {
+ LOG.failedToFilterFieldName( child.field, e );
+ // Write original name.
+ }
+ if( bufferingLevel == null ) {
+ generator.writeFieldName( child.field );
+ }
+ }
+
+ private void processValueString() throws IOException {
+ Level child;
+ Level parent;
+ String value = null;
+ parent = stack.peek();
+ if( parent.isArray() ) {
+ ArrayNode array = (ArrayNode)parent.node;
+ array.add( parser.getText() );
+ if( bufferingLevel == null ) {
+ value = filterStreamValue( parent );
+ array.set( array.size()-1, new TextNode( value ) );
+ } else {
+ array.removeAll();
+ }
+ } else {
+ child = stack.pop();
+ parent = stack.peek();
+ ((ObjectNode)parent.node ).put( child.field, parser.getText() );
+ if( bufferingLevel == null ) {
+ child.node = parent.node; // Populate the JsonNode of the child for filtering.
+ value = filterStreamValue( child );
+ }
+ }
+ if( bufferingLevel == null ) {
+ if( parent.node.isArray() ) {
+ ((ArrayNode)parent.node).removeAll();
+ } else {
+ ((ObjectNode)parent.node).removeAll();
+ }
+ generator.writeString( value );
+ }
+ }
+
+ private void processValueNumber() throws IOException {
+ Level child;
+ Level parent;
+ parent = stack.peek();
+ if( parent.isArray() ) {
+ if( bufferingLevel != null ) {
+ ArrayNode array = (ArrayNode)parent.node;
+ processBufferedArrayValueNumber( array );
+ }
+ } else {
+ child = stack.pop();
+ if( bufferingLevel != null ) {
+ parent = stack.peek();
+ ObjectNode object = (ObjectNode)parent.node;
+ processBufferedFieldValueNumber( child, object );
+ }
+ }
+ if( bufferingLevel == null ) {
+ processedUnbufferedValueNumber();
+ }
+ }
+
+ private void processedUnbufferedValueNumber() throws IOException {
+ switch( parser.getNumberType() ) {
+ case INT:
+ generator.writeNumber( parser.getIntValue() );
+ break;
+ case LONG:
+ generator.writeNumber( parser.getLongValue() );
+ break;
+ case BIG_INTEGER:
+ generator.writeNumber( parser.getBigIntegerValue() );
+ break;
+ case FLOAT:
+ generator.writeNumber( parser.getFloatValue() );
+ break;
+ case DOUBLE:
+ generator.writeNumber( parser.getDoubleValue() );
+ break;
+ case BIG_DECIMAL:
+ generator.writeNumber( parser.getDecimalValue() );
+ break;
+ }
+ }
+
+ private void processBufferedFieldValueNumber( Level child, ObjectNode object ) throws IOException {
+ //object.put( child.field, parser.getDecimalValue() );
+ switch( parser.getNumberType() ) {
+ case INT:
+ object.put( child.field, parser.getIntValue() );
+ break;
+ case LONG:
+ object.put( child.field, parser.getLongValue() );
+ break;
+ case BIG_INTEGER:
+ object.put( child.field, parser.getDecimalValue() );
+ break;
+ case FLOAT:
+ object.put( child.field, parser.getFloatValue() );
+ break;
+ case DOUBLE:
+ object.put( child.field, parser.getDoubleValue() );
+ break;
+ case BIG_DECIMAL:
+ object.put( child.field, parser.getDecimalValue() );
+ break;
+ }
+ }
+
+ private void processBufferedArrayValueNumber( ArrayNode array ) throws IOException {
+ //array.add( parser.getDecimalValue() );
+ switch( parser.getNumberType() ) {
+ case INT:
+ array.add( parser.getIntValue() );
+ break;
+ case LONG:
+ array.add( parser.getLongValue() );
+ break;
+ case BIG_INTEGER:
+ array.add( parser.getDecimalValue() );
+ break;
+ case FLOAT:
+ array.add( parser.getFloatValue() );
+ break;
+ case DOUBLE:
+ array.add( parser.getDoubleValue() );
+ break;
+ case BIG_DECIMAL:
+ array.add( parser.getDecimalValue() );
+ break;
+ }
+ }
+
+ private void processValueBoolean() throws IOException {
+ Level child;
+ Level parent;
+ parent = stack.peek();
+ if( parent.isArray() ) {
+ ((ArrayNode)parent.node ).add( parser.getBooleanValue() );
+ //dump();
+ if( bufferingLevel == null ) {
+ ((ArrayNode)parent.node ).removeAll();
+ }
+ } else {
+ child = stack.pop();
+ parent = stack.peek();
+ ((ObjectNode)parent.node ).put( child.field, parser.getBooleanValue() );
+ //dump();
+ if( bufferingLevel == null ) {
+ ((ObjectNode)parent.node ).remove( child.field );
+ }
+ }
+ if( bufferingLevel == null ) {
+ generator.writeBoolean( parser.getBooleanValue() );
+ }
+ }
+
+ private void processValueNull() throws IOException {
+ Level child;
+ Level parent = stack.peek();
+ if( parent.isArray() ) {
+ ((ArrayNode)parent.node ).addNull();
+ //dump();
+ if( bufferingLevel == null ) {
+ ((ArrayNode)parent.node ).removeAll();
+ }
+ } else {
+ child = stack.pop();
+ parent = stack.peek();
+ ((ObjectNode)parent.node ).putNull( child.field );
+ //dump();
+ if( bufferingLevel == null ) {
+ ((ObjectNode)parent.node ).remove( child.field );
+ }
+ }
+ if( bufferingLevel == null ) {
+ generator.writeNull();
+ }
+ }
+
+ protected boolean startBuffering( Level node ) {
+ boolean buffered = false;
+ UrlRewriteFilterGroupDescriptor scope = node.scopeConfig;
+ if( scope != null ) {
+ for( UrlRewriteFilterPathDescriptor selector : scope.getSelectors() ) {
+ JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
+ List<JsonPath.Match> matches = path.evaluate( node.scopeNode );
+ if( matches != null && matches.size() > 0 ) {
+ if( selector instanceof UrlRewriteFilterBufferDescriptor ) {
+ bufferingLevel = node;
+ bufferingConfig = (UrlRewriteFilterBufferDescriptor)selector;
+ buffered = true;
+ }
+ break;
+ }
+ }
+ }
+ return buffered;
+ }
+
+ protected String filterStreamValue( Level node ) {
+ String value;
+ if( node.isArray() ) {
+ value = node.node.get( 0 ).asText();
+ } else {
+ value = node.node.get( node.field ).asText();
+ }
+ String rule = null;
+ UrlRewriteFilterGroupDescriptor scope = node.scopeConfig;
+ //TODO: Scan the top level apply rules for the first match.
+ if( scope != null ) {
+ for( UrlRewriteFilterPathDescriptor selector : scope.getSelectors() ) {
+ JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
+ List<JsonPath.Match> matches = path.evaluate( node.scopeNode );
+ if( matches != null && matches.size() > 0 ) {
+ JsonPath.Match match = matches.get( 0 );
+ if( match.getNode().isTextual() ) {
+ if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
+ UrlRewriteFilterApplyDescriptor apply = (UrlRewriteFilterApplyDescriptor)selector;
+ rule = apply.rule();
+ break;
+ }
+ }
+ }
+ }
+ }
+ try {
+ value = filterValueString( node.field, value, rule );
+ if( node.isArray() ) {
+ ((ArrayNode)node.node).set( 0, new TextNode( value ) );
+ } else {
+ ((ObjectNode)node.node).put( node.field, value );
+ }
+ } catch( Exception e ) {
+ LOG.failedToFilterValue( value, rule, e );
+ }
+ return value;
+ }
+
+ private void filterBufferedNode( Level node ) {
+ for( UrlRewriteFilterPathDescriptor selector : bufferingConfig.getSelectors() ) {
+ JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
+ List<JsonPath.Match> matches = path.evaluate( node.node );
+ for( JsonPath.Match match : matches ) {
+ if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
+ if( match.getNode().isTextual() ) {
+ filterBufferedValue( match, (UrlRewriteFilterApplyDescriptor)selector );
+ }
+ } else if( selector instanceof UrlRewriteFilterDetectDescriptor ) {
+ UrlRewriteFilterDetectDescriptor detectConfig = (UrlRewriteFilterDetectDescriptor)selector;
+ JsonPath.Expression detectPath = (JsonPath.Expression)detectConfig.compiledPath( JPATH_COMPILER );
+ List<JsonPath.Match> detectMatches = detectPath.evaluate( node.node );
+ for( JsonPath.Match detectMatch : detectMatches ) {
+ if( detectMatch.getNode().isTextual() ) {
+ String detectValue = detectMatch.getNode().asText();
+ Pattern detectPattern = detectConfig.compiledValue( REGEX_COMPILER );
+ if( detectPattern.matcher( detectValue ).matches() ) {
+ filterBufferedValues( node, detectConfig.getSelectors() );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void filterBufferedValues( Level node, List<UrlRewriteFilterPathDescriptor> selectors ) {
+ for( UrlRewriteFilterPathDescriptor selector : selectors ) {
+ JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
+ List<JsonPath.Match> matches = path.evaluate( node.node );
+ for( JsonPath.Match match : matches ) {
+ if( match.getNode().isTextual() ) {
+ if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
+ filterBufferedValue( match, (UrlRewriteFilterApplyDescriptor)selector );
+ }
+ }
+ }
+ }
+ }
+
+ private void filterBufferedValue( JsonPath.Match match, UrlRewriteFilterApplyDescriptor apply ) {
+ String field = match.getField();
+ String value = match.getNode().asText();
+ try {
+ value = filterValueString( field, value, apply.rule() );
+ ((ObjectNode)match.getParent().getNode()).put( field, value );
+ } catch( Exception e ) {
+ LOG.failedToFilterValue( value, apply.rule(), e );
+ }
+ }
+
+ protected String filterFieldName( String field ) {
+ return field;
+ }
+
+ protected String filterValueString( String name, String value, String rule ) {
+ return value;
+ }
+
+ @Override
+ public void close() throws IOException {
+ generator.close();
+ writer.close();
+ parser.close();
+ reader.close();
+ }
+
+ private static class Level {
+ String field;
+ JsonNode node;
+ JsonNode scopeNode;
+ UrlRewriteFilterGroupDescriptor scopeConfig;
+ private Level( String field, JsonNode node, JsonNode scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
+ this.field = field;
+ this.node = node;
+ this.scopeNode = scopeNode;
+ this.scopeConfig = scopeConfig;
+ }
+ public boolean isArray() {
+ return node != null && node.isArray();
+ }
+ }
+
+ private static class JsonPathCompiler implements UrlRewriteFilterPathDescriptor.Compiler<JsonPath.Expression> {
+ @Override
+ public JsonPath.Expression compile( String expression, JsonPath.Expression compiled ) {
+ return JsonPath.compile( expression );
+ }
+ }
+
+ private 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 );
+ }
+ }
+ }
+
+// private void dump() throws IOException {
+// mapper.writeTree( factory.createGenerator( System.out ), stack.get( 0 ).node );
+// System.out.println();
+// }
+
+}
+
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteFilterReader.java
new file mode 100644
index 0000000..463987f
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteFilterReader.java
@@ -0,0 +1,64 @@
+/**
+ * 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.filter.rewrite.impl.json;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.urltemplate.Parser;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+import org.apache.knox.gateway.util.urltemplate.Template;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+public class JsonUrlRewriteFilterReader extends JsonFilterReader {
+
+ private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+ private Resolver resolver;
+ private UrlRewriter rewriter;
+ private UrlRewriter.Direction direction;
+
+ public JsonUrlRewriteFilterReader(
+ 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;
+ }
+
+ protected String filterValueString( String name, String value, String rule ) {
+ try {
+ Template input = Parser.parseLiteral( value );
+ Template output = rewriter.rewrite( resolver, input, direction, rule );
+ value = output.getPattern();
+ } catch( URISyntaxException e ) {
+ LOG.failedToParseValueForUrlRewrite( value );
+ }
+ return value;
+ }
+
+}