blob: 7ba91f47c315718ef7a9371a24c5c3107874f03c [file] [log] [blame]
/**
* 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 org.apache.hadoop.gateway.filter.AbstractGatewayFilter;
import org.apache.hadoop.gateway.filter.GatewayRequestWrapper;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterDescriptor;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteServletContextListener;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteServletFilter;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteStreamFilterFactory;
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.MimeTypes;
import org.apache.hadoop.gateway.util.urltemplate.Parser;
import org.apache.hadoop.gateway.util.urltemplate.Resolver;
import org.apache.hadoop.gateway.util.urltemplate.Template;
import javax.activation.MimeType;
import javax.servlet.FilterConfig;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import static org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteUtil.pickFirstRuleWithEqualsIgnoreCasePathMatch;
public class UrlRewriteRequest extends GatewayRequestWrapper implements Resolver {
private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
private static final String[] EMPTY_STRING_ARRAY = new String[]{};
private FilterConfig config;
private UrlRewriter rewriter;
private String urlRuleName;
private String bodyFilterName;
private String headersFilterName;
private UrlRewriteFilterContentDescriptor headersFilterConfig;
private String cookiesFilterName;
private UrlRewriteFilterContentDescriptor cookiesFilterConfig;
/**
* Constructs a request object wrapping the given request.
*
* @throws IllegalArgumentException if the request is null
*/
public UrlRewriteRequest( FilterConfig config, HttpServletRequest request ) throws IOException {
super( request );
this.config = config;
this.rewriter = UrlRewriteServletContextListener.getUrlRewriter( config.getServletContext() );
this.urlRuleName = config.getInitParameter( UrlRewriteServletFilter.REQUEST_URL_RULE_PARAM );
this.bodyFilterName = config.getInitParameter( UrlRewriteServletFilter.REQUEST_BODY_FILTER_PARAM );
this.headersFilterName = config.getInitParameter( UrlRewriteServletFilter.REQUEST_HEADERS_FILTER_PARAM );
this.headersFilterConfig = getRewriteFilterConfig( headersFilterName, UrlRewriteServletFilter.HEADERS_MIME_TYPE );
this.cookiesFilterName = config.getInitParameter( UrlRewriteServletFilter.REQUEST_COOKIES_FILTER_PARAM );
this.cookiesFilterConfig = getRewriteFilterConfig( cookiesFilterName, UrlRewriteServletFilter.COOKIES_MIME_TYPE );
}
private Template getSourceUrl() {
Template urlTemplate;
//KNOX-439[
//StringBuffer urlString = super.getRequestURL();
StringBuffer urlString = new StringBuffer( 128 );
urlString.append( getScheme() );
urlString.append( "://" );
urlString.append( getServerName() );
urlString.append( ":" );
urlString.append( getServerPort() );
urlString.append( super.getRequestURI() );
//]
String queryString = super.getQueryString();
if( queryString != null ) {
urlString.append( '?' );
urlString.append( queryString );
}
try {
urlTemplate = Parser.parseLiteral( urlString.toString() );
} catch( URISyntaxException e ) {
LOG.failedToParseValueForUrlRewrite( urlString.toString() );
// Shouldn't be possible given that the URL is constructed from parts of an existing URL.
urlTemplate = null;
}
return urlTemplate;
}
// Note: Source url was added to the request attributes by the GatewayFilter doFilter method.
private Template getTargetUrl() {
boolean rewriteRequestUrl = true;
Template targetUrl;
if( rewriteRequestUrl ) {
targetUrl = (Template)getAttribute( AbstractGatewayFilter.TARGET_REQUEST_URL_ATTRIBUTE_NAME );
if( targetUrl == null ) {
Template sourceUrl = getSourceUrl();
targetUrl = rewriter.rewrite( this, sourceUrl, UrlRewriter.Direction.IN, urlRuleName );
setAttribute( AbstractGatewayFilter.TARGET_REQUEST_URL_ATTRIBUTE_NAME, targetUrl );
}
} else {
targetUrl = (Template)getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_URL_ATTRIBUTE_NAME );
}
return targetUrl;
}
private String[] splitTargetUrl( Template url ) {
if( url == null ) {
return EMPTY_STRING_ARRAY;
} else {
String s = url.toEncodedString();
return s.split( "\\?" );
}
}
@Override
public StringBuffer getRequestURL() {
return new StringBuffer( getRequestURI() );
}
//TODO: I think this method is implemented wrong based on the HttpServletRequest.getRequestURI docs.
// It should not include the scheme or authority parts.
@Override
public String getRequestURI() {
String[] split = splitTargetUrl( getTargetUrl() );
if( split.length > 0 ) {
return split[0];
} else {
return "";
}
}
@Override
public String getQueryString() {
String[] split = splitTargetUrl( getTargetUrl() );
if( split.length > 1 ) {
return split[1];
} else {
return null;
}
}
private String rewriteValue( UrlRewriter rewriter, String value, String rule ) {
try {
Template input = Parser.parseLiteral( value );
Template output = rewriter.rewrite( this, input, UrlRewriter.Direction.IN, rule );
value = output.getPattern();
} catch( URISyntaxException e ) {
LOG.failedToParseValueForUrlRewrite( value );
}
return value;
}
@Override
public String getHeader( String name ) {
String value = super.getHeader( name );
if( value != null ) {
value = rewriteValue( rewriter, super.getHeader( name ), pickFirstRuleWithEqualsIgnoreCasePathMatch( headersFilterConfig, name ) );
}
return value;
}
@SuppressWarnings("unchecked")
public Enumeration getHeaders( String name ) {
return new EnumerationRewriter( rewriter, super.getHeaders( name ), pickFirstRuleWithEqualsIgnoreCasePathMatch( headersFilterConfig, name ) );
}
@Override
public List<String> resolve( String name ) {
return Arrays.asList( config.getInitParameter( name ) );
}
private class EnumerationRewriter implements Enumeration<String> {
private UrlRewriter rewriter;
private Enumeration<String> delegate;
private String rule;
private EnumerationRewriter( UrlRewriter rewriter, Enumeration<String> delegate, String rule ) {
this.rewriter = rewriter;
this.delegate = delegate;
this.rule = rule;
}
@Override
public boolean hasMoreElements() {
return delegate.hasMoreElements();
}
@Override
public String nextElement() {
return rewriteValue( rewriter, delegate.nextElement(), rule );
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream input = super.getInputStream();
if( getContentLength() != 0 ) {
MimeType mimeType = getMimeType();
UrlRewriteFilterContentDescriptor filterContentConfig = getRewriteFilterConfig( bodyFilterName, mimeType );
if (filterContentConfig != null) {
String asType = filterContentConfig.asType();
if ( asType != null && asType.trim().length() > 0 ) {
mimeType = MimeTypes.create(asType, getCharacterEncoding());
}
}
InputStream stream = UrlRewriteStreamFilterFactory.create( mimeType, null, input, rewriter, this, UrlRewriter.Direction.IN, filterContentConfig );
input = new UrlRewriteRequestStream( stream );
}
return input;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader( new InputStreamReader( getInputStream(), getCharacterEncoding() ) );
}
@Override
public int getContentLength() {
// The rewrite might change the content length so return the default of -1 to indicate the length is unknown.
int contentLength = super.getContentLength();
if( contentLength > 0 ) {
contentLength = -1;
}
return contentLength;
}
private UrlRewriteFilterContentDescriptor getRewriteFilterConfig( String filterName, MimeType mimeType ) {
UrlRewriteFilterContentDescriptor filterContentConfig = null;
UrlRewriteRulesDescriptor rewriteConfig = rewriter.getConfig();
if( rewriteConfig != null ) {
UrlRewriteFilterDescriptor filterConfig = rewriteConfig.getFilter( filterName );
if( filterConfig != null ) {
filterContentConfig = filterConfig.getContent( mimeType );
}
}
return filterContentConfig;
}
}