init
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# 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.
|
||||
|
||||
rewriteValve.closeError=Error closing configuration
|
||||
rewriteValve.invalidFlags=Invalid flag in [{0}] flags [{1}]
|
||||
rewriteValve.invalidLine=Invalid line [{0}]
|
||||
rewriteValve.invalidMapClassName=Invalid map class name [{0}]
|
||||
rewriteValve.readError=Error reading configuration
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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.
|
||||
|
||||
rewriteValve.closeError=Erreur lors de la fermeture de la configuration
|
||||
rewriteValve.invalidFlags=Indicateur invalide dans [{0}] indicateurs [{1}]
|
||||
rewriteValve.invalidLine=Ligne invalide [{0}]
|
||||
rewriteValve.invalidMapClassName=Le nom de la classe [{0}] de la structure est invalide
|
||||
rewriteValve.readError=Erreur lors de la lecture de la configuration
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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.
|
||||
|
||||
rewriteValve.closeError=構成を閉じる際のエラー
|
||||
rewriteValve.invalidFlags=[{0}]に無効なフラグ [{1}]があります。
|
||||
rewriteValve.invalidLine=無効な行[{0}]
|
||||
rewriteValve.invalidMapClassName=Mapクラス名[{0}]が無効です。
|
||||
rewriteValve.readError=構成の読み取りエラー
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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.
|
||||
|
||||
rewriteValve.closeError=설정 리소스의 스트림을 닫는 중 오류 발생
|
||||
rewriteValve.invalidFlags=[{0}] 내에 유효하지 않은 플래그입니다 (플래그들: [{1}]).
|
||||
rewriteValve.invalidLine=유효하지 않은 행 [{0}]
|
||||
rewriteValve.invalidMapClassName=유효하지 않은 Map 클래스 이름: [{0}]
|
||||
rewriteValve.readError=설정을 읽는 도중 오류 발생
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
rewriteValve.readError=读取配置时发生异常
|
||||
48
java/org/apache/catalina/valves/rewrite/Resolver.java
Normal file
48
java/org/apache/catalina/valves/rewrite/Resolver.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.catalina.valves.rewrite;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Resolver abstract class.
|
||||
*/
|
||||
public abstract class Resolver {
|
||||
|
||||
public abstract String resolve(String key);
|
||||
|
||||
public String resolveEnv(String key) {
|
||||
return System.getProperty(key);
|
||||
}
|
||||
|
||||
public abstract String resolveSsl(String key);
|
||||
|
||||
public abstract String resolveHttp(String key);
|
||||
|
||||
public abstract boolean resolveResource(int type, String name);
|
||||
|
||||
/**
|
||||
* @return The name of the encoding to use to %nn encode URIs
|
||||
*
|
||||
* @deprecated This will be removed in Tomcat 9.0.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract String getUriEncoding();
|
||||
|
||||
public abstract Charset getUriCharset();
|
||||
}
|
||||
191
java/org/apache/catalina/valves/rewrite/ResolverImpl.java
Normal file
191
java/org/apache/catalina/valves/rewrite/ResolverImpl.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.catalina.valves.rewrite;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.catalina.WebResource;
|
||||
import org.apache.catalina.WebResourceRoot;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.tomcat.util.http.FastHttpDateFormat;
|
||||
|
||||
public class ResolverImpl extends Resolver {
|
||||
|
||||
protected Request request = null;
|
||||
|
||||
public ResolverImpl(Request request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following are not implemented:
|
||||
* - SERVER_ADMIN
|
||||
* - API_VERSION
|
||||
* - IS_SUBREQ
|
||||
*/
|
||||
@Override
|
||||
public String resolve(String key) {
|
||||
if (key.equals("HTTP_USER_AGENT")) {
|
||||
return request.getHeader("user-agent");
|
||||
} else if (key.equals("HTTP_REFERER")) {
|
||||
return request.getHeader("referer");
|
||||
} else if (key.equals("HTTP_COOKIE")) {
|
||||
return request.getHeader("cookie");
|
||||
} else if (key.equals("HTTP_FORWARDED")) {
|
||||
return request.getHeader("forwarded");
|
||||
} else if (key.equals("HTTP_HOST")) {
|
||||
String host = request.getHeader("host");
|
||||
if (host != null) {
|
||||
int index = host.indexOf(':');
|
||||
if (index != -1) {
|
||||
host = host.substring(0, index);
|
||||
}
|
||||
}
|
||||
return host;
|
||||
} else if (key.equals("HTTP_PROXY_CONNECTION")) {
|
||||
return request.getHeader("proxy-connection");
|
||||
} else if (key.equals("HTTP_ACCEPT")) {
|
||||
return request.getHeader("accept");
|
||||
} else if (key.equals("REMOTE_ADDR")) {
|
||||
return request.getRemoteAddr();
|
||||
} else if (key.equals("REMOTE_HOST")) {
|
||||
return request.getRemoteHost();
|
||||
} else if (key.equals("REMOTE_PORT")) {
|
||||
return String.valueOf(request.getRemotePort());
|
||||
} else if (key.equals("REMOTE_USER")) {
|
||||
return request.getRemoteUser();
|
||||
} else if (key.equals("REMOTE_IDENT")) {
|
||||
return request.getRemoteUser();
|
||||
} else if (key.equals("REQUEST_METHOD")) {
|
||||
return request.getMethod();
|
||||
} else if (key.equals("SCRIPT_FILENAME")) {
|
||||
return request.getServletContext().getRealPath(request.getServletPath());
|
||||
} else if (key.equals("REQUEST_PATH")) {
|
||||
return request.getRequestPathMB().toString();
|
||||
} else if (key.equals("CONTEXT_PATH")) {
|
||||
return request.getContextPath();
|
||||
} else if (key.equals("SERVLET_PATH")) {
|
||||
return emptyStringIfNull(request.getServletPath());
|
||||
} else if (key.equals("PATH_INFO")) {
|
||||
return emptyStringIfNull(request.getPathInfo());
|
||||
} else if (key.equals("QUERY_STRING")) {
|
||||
return emptyStringIfNull(request.getQueryString());
|
||||
} else if (key.equals("AUTH_TYPE")) {
|
||||
return request.getAuthType();
|
||||
} else if (key.equals("DOCUMENT_ROOT")) {
|
||||
return request.getServletContext().getRealPath("/");
|
||||
} else if (key.equals("SERVER_NAME")) {
|
||||
return request.getLocalName();
|
||||
} else if (key.equals("SERVER_ADDR")) {
|
||||
return request.getLocalAddr();
|
||||
} else if (key.equals("SERVER_PORT")) {
|
||||
return String.valueOf(request.getLocalPort());
|
||||
} else if (key.equals("SERVER_PROTOCOL")) {
|
||||
return request.getProtocol();
|
||||
} else if (key.equals("SERVER_SOFTWARE")) {
|
||||
return "tomcat";
|
||||
} else if (key.equals("THE_REQUEST")) {
|
||||
return request.getMethod() + " " + request.getRequestURI()
|
||||
+ " " + request.getProtocol();
|
||||
} else if (key.equals("REQUEST_URI")) {
|
||||
return request.getRequestURI();
|
||||
} else if (key.equals("REQUEST_FILENAME")) {
|
||||
return request.getPathTranslated();
|
||||
} else if (key.equals("HTTPS")) {
|
||||
return request.isSecure() ? "on" : "off";
|
||||
} else if (key.equals("TIME_YEAR")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
|
||||
} else if (key.equals("TIME_MON")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.MONTH));
|
||||
} else if (key.equals("TIME_DAY")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
|
||||
} else if (key.equals("TIME_HOUR")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
|
||||
} else if (key.equals("TIME_MIN")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.MINUTE));
|
||||
} else if (key.equals("TIME_SEC")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.SECOND));
|
||||
} else if (key.equals("TIME_WDAY")) {
|
||||
return String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_WEEK));
|
||||
} else if (key.equals("TIME")) {
|
||||
return FastHttpDateFormat.getCurrentDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveEnv(String key) {
|
||||
Object result = request.getAttribute(key);
|
||||
return (result != null) ? result.toString() : System.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveSsl(String key) {
|
||||
// FIXME: Implement SSL environment variables
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveHttp(String key) {
|
||||
String header = request.getHeader(key);
|
||||
if (header == null) {
|
||||
return "";
|
||||
} else {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resolveResource(int type, String name) {
|
||||
WebResourceRoot resources = request.getContext().getResources();
|
||||
WebResource resource = resources.getResource(name);
|
||||
if (!resource.exists()) {
|
||||
return false;
|
||||
} else {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return resource.isDirectory();
|
||||
case 1:
|
||||
return resource.isFile();
|
||||
case 2:
|
||||
return resource.isFile() && resource.getContentLength() > 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String emptyStringIfNull(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String getUriEncoding() {
|
||||
return request.getConnector().getURIEncoding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Charset getUriCharset() {
|
||||
return request.getConnector().getURICharset();
|
||||
}
|
||||
}
|
||||
239
java/org/apache/catalina/valves/rewrite/RewriteCond.java
Normal file
239
java/org/apache/catalina/valves/rewrite/RewriteCond.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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.catalina.valves.rewrite;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RewriteCond {
|
||||
|
||||
public abstract static class Condition {
|
||||
public abstract boolean evaluate(String value, Resolver resolver);
|
||||
}
|
||||
|
||||
public static class PatternCondition extends Condition {
|
||||
public Pattern pattern;
|
||||
private ThreadLocal<Matcher> matcher = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public boolean evaluate(String value, Resolver resolver) {
|
||||
Matcher m = pattern.matcher(value);
|
||||
if (m.matches()) {
|
||||
matcher.set(m);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Matcher getMatcher() {
|
||||
return matcher.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static class LexicalCondition extends Condition {
|
||||
/**
|
||||
* -1: <
|
||||
* 0: =
|
||||
* 1: >
|
||||
*/
|
||||
public int type = 0;
|
||||
public String condition;
|
||||
|
||||
@Override
|
||||
public boolean evaluate(String value, Resolver resolver) {
|
||||
int result = value.compareTo(condition);
|
||||
switch (type) {
|
||||
case -1:
|
||||
return (result < 0);
|
||||
case 0:
|
||||
return (result == 0);
|
||||
case 1:
|
||||
return (result > 0);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResourceCondition extends Condition {
|
||||
/**
|
||||
* 0: -d (is directory ?)
|
||||
* 1: -f (is regular file ?)
|
||||
* 2: -s (is regular file with size ?)
|
||||
*/
|
||||
public int type = 0;
|
||||
|
||||
@Override
|
||||
public boolean evaluate(String value, Resolver resolver) {
|
||||
return resolver.resolveResource(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected String testString = null;
|
||||
protected String condPattern = null;
|
||||
protected String flagsString = null;
|
||||
|
||||
public String getCondPattern() {
|
||||
return condPattern;
|
||||
}
|
||||
|
||||
public void setCondPattern(String condPattern) {
|
||||
this.condPattern = condPattern;
|
||||
}
|
||||
|
||||
public String getTestString() {
|
||||
return testString;
|
||||
}
|
||||
|
||||
public void setTestString(String testString) {
|
||||
this.testString = testString;
|
||||
}
|
||||
|
||||
public final String getFlagsString() {
|
||||
return flagsString;
|
||||
}
|
||||
|
||||
public final void setFlagsString(String flagsString) {
|
||||
this.flagsString = flagsString;
|
||||
}
|
||||
|
||||
public void parse(Map<String, RewriteMap> maps) {
|
||||
test = new Substitution();
|
||||
test.setSub(testString);
|
||||
test.parse(maps);
|
||||
if (condPattern.startsWith("!")) {
|
||||
positive = false;
|
||||
condPattern = condPattern.substring(1);
|
||||
}
|
||||
if (condPattern.startsWith("<")) {
|
||||
LexicalCondition ncondition = new LexicalCondition();
|
||||
ncondition.type = -1;
|
||||
ncondition.condition = condPattern.substring(1);
|
||||
this.condition = ncondition;
|
||||
} else if (condPattern.startsWith(">")) {
|
||||
LexicalCondition ncondition = new LexicalCondition();
|
||||
ncondition.type = 1;
|
||||
ncondition.condition = condPattern.substring(1);
|
||||
this.condition = ncondition;
|
||||
} else if (condPattern.startsWith("=")) {
|
||||
LexicalCondition ncondition = new LexicalCondition();
|
||||
ncondition.type = 0;
|
||||
ncondition.condition = condPattern.substring(1);
|
||||
this.condition = ncondition;
|
||||
} else if (condPattern.equals("-d")) {
|
||||
ResourceCondition ncondition = new ResourceCondition();
|
||||
ncondition.type = 0;
|
||||
this.condition = ncondition;
|
||||
} else if (condPattern.equals("-f")) {
|
||||
ResourceCondition ncondition = new ResourceCondition();
|
||||
ncondition.type = 1;
|
||||
this.condition = ncondition;
|
||||
} else if (condPattern.equals("-s")) {
|
||||
ResourceCondition ncondition = new ResourceCondition();
|
||||
ncondition.type = 2;
|
||||
this.condition = ncondition;
|
||||
} else {
|
||||
PatternCondition ncondition = new PatternCondition();
|
||||
int flags = 0;
|
||||
if (isNocase()) {
|
||||
flags |= Pattern.CASE_INSENSITIVE;
|
||||
}
|
||||
ncondition.pattern = Pattern.compile(condPattern, flags);
|
||||
this.condition = ncondition;
|
||||
}
|
||||
}
|
||||
|
||||
public Matcher getMatcher() {
|
||||
if (condition instanceof PatternCondition) {
|
||||
return ((PatternCondition) condition).getMatcher();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RewriteCond " + testString + " " + condPattern
|
||||
+ ((flagsString != null) ? (" " + flagsString) : "");
|
||||
}
|
||||
|
||||
|
||||
protected boolean positive = true;
|
||||
|
||||
protected Substitution test = null;
|
||||
|
||||
protected Condition condition = null;
|
||||
|
||||
/**
|
||||
* This makes the test case-insensitive, i.e., there is no difference between
|
||||
* 'A-Z' and 'a-z' both in the expanded TestString and the CondPattern. This
|
||||
* flag is effective only for comparisons between TestString and CondPattern.
|
||||
* It has no effect on filesystem and subrequest checks.
|
||||
*/
|
||||
public boolean nocase = false;
|
||||
|
||||
/**
|
||||
* Use this to combine rule conditions with a local OR instead of the implicit AND.
|
||||
*/
|
||||
public boolean ornext = false;
|
||||
|
||||
/**
|
||||
* Evaluate the condition based on the context
|
||||
*
|
||||
* @param rule corresponding matched rule
|
||||
* @param cond last matched condition
|
||||
* @param resolver Property resolver
|
||||
* @return <code>true</code> if the condition matches
|
||||
*/
|
||||
public boolean evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
String value = test.evaluate(rule, cond, resolver);
|
||||
if (positive) {
|
||||
return condition.evaluate(value, resolver);
|
||||
} else {
|
||||
return !condition.evaluate(value, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNocase() {
|
||||
return nocase;
|
||||
}
|
||||
|
||||
public void setNocase(boolean nocase) {
|
||||
this.nocase = nocase;
|
||||
}
|
||||
|
||||
public boolean isOrnext() {
|
||||
return ornext;
|
||||
}
|
||||
|
||||
public void setOrnext(boolean ornext) {
|
||||
this.ornext = ornext;
|
||||
}
|
||||
|
||||
public boolean isPositive() {
|
||||
return positive;
|
||||
}
|
||||
|
||||
public void setPositive(boolean positive) {
|
||||
this.positive = positive;
|
||||
}
|
||||
}
|
||||
24
java/org/apache/catalina/valves/rewrite/RewriteMap.java
Normal file
24
java/org/apache/catalina/valves/rewrite/RewriteMap.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.catalina.valves.rewrite;
|
||||
|
||||
public interface RewriteMap {
|
||||
|
||||
public String setParameters(String params);
|
||||
|
||||
public String lookup(String key);
|
||||
}
|
||||
563
java/org/apache/catalina/valves/rewrite/RewriteRule.java
Normal file
563
java/org/apache/catalina/valves/rewrite/RewriteRule.java
Normal file
File diff suppressed because it is too large
Load Diff
845
java/org/apache/catalina/valves/rewrite/RewriteValve.java
Normal file
845
java/org/apache/catalina/valves/rewrite/RewriteValve.java
Normal file
File diff suppressed because it is too large
Load Diff
347
java/org/apache/catalina/valves/rewrite/Substitution.java
Normal file
347
java/org/apache/catalina/valves/rewrite/Substitution.java
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* 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.catalina.valves.rewrite;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.apache.catalina.util.URLEncoder;
|
||||
|
||||
public class Substitution {
|
||||
|
||||
public abstract class SubstitutionElement {
|
||||
public abstract String evaluate(Matcher rule, Matcher cond, Resolver resolver);
|
||||
}
|
||||
|
||||
public class StaticElement extends SubstitutionElement {
|
||||
public String value;
|
||||
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class RewriteRuleBackReferenceElement extends SubstitutionElement {
|
||||
public int n;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
String result = rule.group(n);
|
||||
if (result == null) {
|
||||
result = "";
|
||||
}
|
||||
if (escapeBackReferences) {
|
||||
// Note: This should be consistent with the way httpd behaves.
|
||||
// We might want to consider providing a dedicated decoder
|
||||
// with an option to add additional safe characters to
|
||||
// provide users with more flexibility
|
||||
return URLEncoder.DEFAULT.encode(result, resolver.getUriCharset());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RewriteCondBackReferenceElement extends SubstitutionElement {
|
||||
public int n;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return (cond.group(n) == null ? "" : cond.group(n));
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerVariableElement extends SubstitutionElement {
|
||||
public String key;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return resolver.resolve(key);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerVariableEnvElement extends SubstitutionElement {
|
||||
public String key;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return resolver.resolveEnv(key);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerVariableSslElement extends SubstitutionElement {
|
||||
public String key;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return resolver.resolveSsl(key);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerVariableHttpElement extends SubstitutionElement {
|
||||
public String key;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return resolver.resolveHttp(key);
|
||||
}
|
||||
}
|
||||
|
||||
public class MapElement extends SubstitutionElement {
|
||||
public RewriteMap map = null;
|
||||
public SubstitutionElement[] defaultValue = null;
|
||||
public SubstitutionElement[] key = null;
|
||||
@Override
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
String result = map.lookup(evaluateSubstitution(key, rule, cond, resolver));
|
||||
if (result == null && defaultValue != null) {
|
||||
result = evaluateSubstitution(defaultValue, rule, cond, resolver);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
protected SubstitutionElement[] elements = null;
|
||||
|
||||
protected String sub = null;
|
||||
public String getSub() { return sub; }
|
||||
public void setSub(String sub) { this.sub = sub; }
|
||||
|
||||
private boolean escapeBackReferences;
|
||||
void setEscapeBackReferences(boolean escapeBackReferences) {
|
||||
this.escapeBackReferences = escapeBackReferences;
|
||||
}
|
||||
|
||||
public void parse(Map<String, RewriteMap> maps) {
|
||||
this.elements = parseSubtitution(sub, maps);
|
||||
}
|
||||
|
||||
private SubstitutionElement[] parseSubtitution(String sub, Map<String, RewriteMap> maps) {
|
||||
|
||||
List<SubstitutionElement> elements = new ArrayList<>();
|
||||
int pos = 0;
|
||||
int percentPos = 0;
|
||||
int dollarPos = 0;
|
||||
int backslashPos = 0;
|
||||
|
||||
while (pos < sub.length()) {
|
||||
percentPos = sub.indexOf('%', pos);
|
||||
dollarPos = sub.indexOf('$', pos);
|
||||
backslashPos = sub.indexOf('\\', pos);
|
||||
if (percentPos == -1 && dollarPos == -1 && backslashPos == -1) {
|
||||
// Static text
|
||||
StaticElement newElement = new StaticElement();
|
||||
newElement.value = sub.substring(pos, sub.length());
|
||||
pos = sub.length();
|
||||
elements.add(newElement);
|
||||
} else if (isFirstPos(backslashPos, dollarPos, percentPos)) {
|
||||
if (backslashPos + 1 == sub.length()) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
StaticElement newElement = new StaticElement();
|
||||
newElement.value = sub.substring(pos, backslashPos) + sub.substring(backslashPos + 1, backslashPos + 2);
|
||||
pos = backslashPos + 2;
|
||||
elements.add(newElement);
|
||||
} else if (isFirstPos(dollarPos, percentPos)) {
|
||||
// $: back reference to rule or map lookup
|
||||
if (dollarPos + 1 == sub.length()) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
if (pos < dollarPos) {
|
||||
// Static text
|
||||
StaticElement newElement = new StaticElement();
|
||||
newElement.value = sub.substring(pos, dollarPos);
|
||||
pos = dollarPos;
|
||||
elements.add(newElement);
|
||||
}
|
||||
if (Character.isDigit(sub.charAt(dollarPos + 1))) {
|
||||
// $: back reference to rule
|
||||
RewriteRuleBackReferenceElement newElement = new RewriteRuleBackReferenceElement();
|
||||
newElement.n = Character.digit(sub.charAt(dollarPos + 1), 10);
|
||||
pos = dollarPos + 2;
|
||||
elements.add(newElement);
|
||||
} else if (sub.charAt(dollarPos + 1) == '{') {
|
||||
// $: map lookup as ${mapname:key|default}
|
||||
MapElement newElement = new MapElement();
|
||||
int open = sub.indexOf('{', dollarPos);
|
||||
int colon = findMatchingColonOrBar(true, sub, open);
|
||||
int def = findMatchingColonOrBar(false, sub, open);
|
||||
int close = findMatchingBrace(sub, open);
|
||||
if (!(-1 < open && open < colon && colon < close)) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
newElement.map = maps.get(sub.substring(open + 1, colon));
|
||||
if (newElement.map == null) {
|
||||
throw new IllegalArgumentException(sub + ": No map: " + sub.substring(open + 1, colon));
|
||||
}
|
||||
String key = null;
|
||||
String defaultValue = null;
|
||||
if (def > -1) {
|
||||
if (!(colon < def && def < close)) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
key = sub.substring(colon + 1, def);
|
||||
defaultValue = sub.substring(def + 1, close);
|
||||
} else {
|
||||
key = sub.substring(colon + 1, close);
|
||||
}
|
||||
newElement.key = parseSubtitution(key, maps);
|
||||
if (defaultValue != null) {
|
||||
newElement.defaultValue = parseSubtitution(defaultValue, maps);
|
||||
}
|
||||
pos = close + 1;
|
||||
elements.add(newElement);
|
||||
} else {
|
||||
throw new IllegalArgumentException(sub + ": missing digit or curly brace.");
|
||||
}
|
||||
} else {
|
||||
// %: back reference to condition or server variable
|
||||
if (percentPos + 1 == sub.length()) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
if (pos < percentPos) {
|
||||
// Static text
|
||||
StaticElement newElement = new StaticElement();
|
||||
newElement.value = sub.substring(pos, percentPos);
|
||||
pos = percentPos;
|
||||
elements.add(newElement);
|
||||
}
|
||||
if (Character.isDigit(sub.charAt(percentPos + 1))) {
|
||||
// %: back reference to condition
|
||||
RewriteCondBackReferenceElement newElement = new RewriteCondBackReferenceElement();
|
||||
newElement.n = Character.digit(sub.charAt(percentPos + 1), 10);
|
||||
pos = percentPos + 2;
|
||||
elements.add(newElement);
|
||||
} else if (sub.charAt(percentPos + 1) == '{') {
|
||||
// %: server variable as %{variable}
|
||||
SubstitutionElement newElement = null;
|
||||
int open = sub.indexOf('{', percentPos);
|
||||
int colon = findMatchingColonOrBar(true, sub, open);
|
||||
int close = findMatchingBrace(sub, open);
|
||||
if (!(-1 < open && open < close)) {
|
||||
throw new IllegalArgumentException(sub);
|
||||
}
|
||||
if (colon > -1 && open < colon && colon < close) {
|
||||
String type = sub.substring(open + 1, colon);
|
||||
if (type.equals("ENV")) {
|
||||
newElement = new ServerVariableEnvElement();
|
||||
((ServerVariableEnvElement) newElement).key = sub.substring(colon + 1, close);
|
||||
} else if (type.equals("SSL")) {
|
||||
newElement = new ServerVariableSslElement();
|
||||
((ServerVariableSslElement) newElement).key = sub.substring(colon + 1, close);
|
||||
} else if (type.equals("HTTP")) {
|
||||
newElement = new ServerVariableHttpElement();
|
||||
((ServerVariableHttpElement) newElement).key = sub.substring(colon + 1, close);
|
||||
} else {
|
||||
throw new IllegalArgumentException(sub + ": Bad type: " + type);
|
||||
}
|
||||
} else {
|
||||
newElement = new ServerVariableElement();
|
||||
((ServerVariableElement) newElement).key = sub.substring(open + 1, close);
|
||||
}
|
||||
pos = close + 1;
|
||||
elements.add(newElement);
|
||||
} else {
|
||||
throw new IllegalArgumentException(sub + ": missing digit or curly brace.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elements.toArray(new SubstitutionElement[0]);
|
||||
|
||||
}
|
||||
|
||||
private static int findMatchingBrace(String sub, int start) {
|
||||
int nesting = 1;
|
||||
for (int i = start + 1; i < sub.length(); i++) {
|
||||
char c = sub.charAt(i);
|
||||
if (c == '{') {
|
||||
char previousChar = sub.charAt(i-1);
|
||||
if (previousChar == '$' || previousChar == '%') {
|
||||
nesting++;
|
||||
}
|
||||
} else if (c == '}') {
|
||||
nesting--;
|
||||
if (nesting == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int findMatchingColonOrBar(boolean colon, String sub, int start) {
|
||||
int nesting = 0;
|
||||
for (int i = start + 1; i < sub.length(); i++) {
|
||||
char c = sub.charAt(i);
|
||||
if (c == '{') {
|
||||
char previousChar = sub.charAt(i-1);
|
||||
if (previousChar == '$' || previousChar == '%') {
|
||||
nesting++;
|
||||
}
|
||||
} else if (c == '}') {
|
||||
nesting--;
|
||||
} else if (colon ? c == ':' : c =='|') {
|
||||
if (nesting == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the substitution based on the context.
|
||||
* @param rule corresponding matched rule
|
||||
* @param cond last matched condition
|
||||
* @param resolver The property resolver
|
||||
* @return The substitution result
|
||||
*/
|
||||
public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
|
||||
return evaluateSubstitution(elements, rule, cond, resolver);
|
||||
}
|
||||
|
||||
private String evaluateSubstitution(SubstitutionElement[] elements, Matcher rule, Matcher cond, Resolver resolver) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
buf.append(elements[i].evaluate(rule, cond, resolver));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the first int is non negative and smaller than any non negative other int
|
||||
* given with {@code others}.
|
||||
*
|
||||
* @param testPos
|
||||
* integer to test against
|
||||
* @param others
|
||||
* list of integers that are paired against {@code testPos}. Any
|
||||
* negative integer will be ignored.
|
||||
* @return {@code true} if {@code testPos} is not negative and is less then any given other
|
||||
* integer, {@code false} otherwise
|
||||
*/
|
||||
private boolean isFirstPos(int testPos, int... others) {
|
||||
if (testPos < 0) {
|
||||
return false;
|
||||
}
|
||||
for (int other : others) {
|
||||
if (other >= 0 && other < testPos) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
|
||||
<mbean name="RewriteValve"
|
||||
description="A URL rewrite valve"
|
||||
domain="Catalina"
|
||||
group="Valve"
|
||||
type="org.apache.catalina.valves.rewrite.RewriteValve">
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="configuration"
|
||||
description="Rewrite configuration"
|
||||
type="java.lang.String" />
|
||||
|
||||
</mbean>
|
||||
|
||||
</mbeans-descriptors>
|
||||
Reference in New Issue
Block a user