From: <jbo...@li...> - 2005-10-23 16:31:33
|
Author: rem...@jb... Date: 2005-10-23 12:31:25 -0400 (Sun, 23 Oct 2005) New Revision: 1435 Modified: trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteRule.java trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteValve.java trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/Substitution.java Log: - Add the rewrite code for backup purposes (not functional yet, though), part 2. Modified: trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteRule.java =================================================================== --- trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteRule.java 2005-10-22 16:24:05 UTC (rev 1434) +++ trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteRule.java 2005-10-23 16:31:25 UTC (rev 1435) @@ -9,7 +9,6 @@ protected RewriteCond[] conditions = new RewriteCond[0]; protected ThreadLocal pattern = new ThreadLocal(); - //protected Matcher matcher = null; protected Substitution substitution = null; protected String patternString = null; Modified: trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteValve.java =================================================================== --- trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteValve.java 2005-10-22 16:24:05 UTC (rev 1434) +++ trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/RewriteValve.java 2005-10-23 16:31:25 UTC (rev 1435) @@ -1,10 +1,22 @@ package org.jboss.web.rewrite; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; import javax.servlet.ServletException; +import org.apache.catalina.Container; +import org.apache.catalina.Context; import org.apache.catalina.Engine; +import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; @@ -13,6 +25,7 @@ import org.apache.catalina.connector.Response; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.valves.ValveBase; +import org.xml.sax.InputSource; public class RewriteValve extends ValveBase implements Lifecycle { @@ -42,6 +55,20 @@ protected ThreadLocal invoked = new ThreadLocal(); + /** + * Relative path to the configuration file. + * Note: If the valve's container is a context, this will be relative to + * /WEB-INF/. + */ + protected String resourcePath = "rewrite.properties"; + + + /** + * Maps to be used by the rules. + */ + protected Map maps = new Hashtable(); + + public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } @@ -55,18 +82,94 @@ } public void start() throws LifecycleException { + + InputStream is = null; + // Process configuration file for this valve + if (getContainer() instanceof Context) { + is = ((Context) getContainer()).getServletContext() + .getResourceAsStream("/WEB-INF/" + resourcePath); + } else { + String resourceName = getHostConfigPath(resourcePath); + File file = new File(getConfigBase(), resourceName); + try { + if (!file.exists()) { + if (resourceName != null) { + // Use getResource and getResourceAsStream + is = getClass().getClassLoader() + .getResourceAsStream(resourceName); + } + } else { + is = new FileInputStream(file); + } + } catch (Exception e) { + container.getLogger().error("Error opening configuration", e); + } + } + + if (is == null) { + // Will use management operations to configure the valve dynamically + return; + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + + ArrayList rules = new ArrayList(); + ArrayList conditions = new ArrayList(); + while (true) { + try { + String line = reader.readLine(); + if (line == null) { + break; + } + Object result = parse(line); + if (result instanceof RewriteRule) { + RewriteRule rule = (RewriteRule) result; + for (int i = 0; i < conditions.size(); i++) { + rule.addCondition((RewriteCond) conditions.get(i)); + } + conditions.clear(); + rules.add(rule); + } else if (result instanceof RewriteCond) { + conditions.add(result); + } else if (result instanceof Object[]) { + maps.put(((Object[]) result)[0], ((Object[]) result)[1]); + } + } catch (IOException e) { + container.getLogger().error("Error reading configuration", e); + } + } + this.rules = (RewriteRule[]) rules.toArray(new RewriteRule[0]); + + try { + reader.close(); + } catch (IOException e) { + container.getLogger().error("Error closing configuration", e); + } + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + container.getLogger().error("Error closing configuration", e); + } + + // Finish parsing the rules + for (int i = 0; i < this.rules.length; i++) { + this.rules[i].parse(maps); + } + } public void stop() throws LifecycleException { - + rules = null; } public void invoke(Request request, Response response) throws IOException, ServletException { - if (rules == null) { + if (rules == null || rules.length == 0) { getNext().invoke(request, response); return; } @@ -125,4 +228,197 @@ } + /** + * Get config base. + */ + protected File getConfigBase() { + File configBase = + new File(System.getProperty("catalina.base"), "conf"); + if (!configBase.exists()) { + return null; + } else { + return configBase; + } + } + + + /** + * Find the configuration path where the rewrite configuration file + * will be stored. + * + * @param resourceName + * @return + */ + protected String getHostConfigPath(String resourceName) { + StringBuffer result = new StringBuffer(); + Container container = getContainer(); + Container host = null; + Container engine = null; + while (container != null) { + if (container instanceof Host) + host = container; + if (container instanceof Engine) + engine = container; + container = container.getParent(); + } + if (engine != null) { + result.append(engine.getName()).append('/'); + } + if (host != null) { + result.append(host.getName()).append('/'); + } + result.append(resourceName); + return result.toString(); + } + + + /** + * This factory method will parse a line formed like: + * RewriteCond TestString CondPattern [Flags] + * Example: + * RewriteCond %{REMOTE_HOST} ^host1.* [OR] + * + * @param rewriteCond + * @return + */ + public static Object parse(String rewriteCond) { + StringTokenizer tokenizer = new StringTokenizer(rewriteCond); + if (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.equals("RewriteCond")) { + RewriteCond condition = new RewriteCond(); + if (tokenizer.countTokens() < 2) { + throw new IllegalArgumentException("Ivalid line: " + rewriteCond); + } + condition.setTestString(tokenizer.nextToken()); + condition.setCondPattern(tokenizer.nextToken()); + if (tokenizer.hasMoreTokens()) { + String flags = tokenizer.nextToken(); + if (flags.startsWith("[") && flags.endsWith("]")) { + flags.substring(1, flags.length() - 1); + } + StringTokenizer flagsTokenizer = new StringTokenizer(flags, ","); + while (flagsTokenizer.hasMoreElements()) { + parseCondFlag(rewriteCond, condition, flagsTokenizer.nextToken()); + } + } + return condition; + } else if (token.equals("RewriteRule")) { + RewriteRule rule = new RewriteRule(); + if (tokenizer.countTokens() < 2) { + throw new IllegalArgumentException("Ivalid line: " + rewriteCond); + } + rule.setPatternString(tokenizer.nextToken()); + rule.setSubstitutionString(tokenizer.nextToken()); + if (tokenizer.hasMoreTokens()) { + String flags = tokenizer.nextToken(); + if (flags.startsWith("[") && flags.endsWith("]")) { + flags.substring(1, flags.length() - 1); + } + StringTokenizer flagsTokenizer = new StringTokenizer(flags, ","); + while (flagsTokenizer.hasMoreElements()) { + parseRuleFlag(rewriteCond, rule, flagsTokenizer.nextToken()); + } + } + return rule; + } else if (token.equals("RewriteMap")) { + // FIXME: Map parsing: return an Object[2] with 0:name 1:RewriteMap + // RewriteMap name rewriteMapClassName;whateverParameterInWhateverFormat + } else { + throw new IllegalArgumentException("Ivalid line: " + rewriteCond); + } + } + return null; + } + + + /** + * Parser for RewriteCond flags. + * + * @param condition + * @param flag + */ + protected static void parseCondFlag(String line, RewriteCond condition, String flag) { + if (flag.equals("NC") || flag.equals("nocase")) { + condition.setNocase(true); + } else if (flag.equals("OR") || flag.equals("ornext")) { + condition.setOrnext(true); + } else { + throw new IllegalArgumentException("Ivalid flag in: " + line); + } + } + + + /** + * Parser for ReweriteRule flags. + * + * @param rule + * @param flag + */ + protected static void parseRuleFlag(String line, RewriteRule rule, String flag) { + if (flag.equals("chain") || flag.equals("C")) { + rule.setChain(true); + } else if (flag.startsWith("cookie=") || flag.startsWith("C=")) { + rule.setCookie(true); + // FIXME: Parse cookie + } else if (flag.startsWith("env=") || flag.startsWith("E=")) { + rule.setEnv(true); + if (flag.startsWith("env=")) { + flag = flag.substring("env=".length()); + } else if (flag.startsWith("E=")) { + flag = flag.substring("E=".length()); + } + int pos = flag.indexOf(':'); + if (pos == -1 || (pos + 1) == flag.length()) { + throw new IllegalArgumentException("Ivalid flag in: " + line); + } + rule.setEnvName(flag.substring(0, pos)); + rule.setEnvValue(flag.substring(pos + 1)); + } else if (flag.startsWith("forbidden") || flag.startsWith("F")) { + rule.setForbidden(true); + } else if (flag.startsWith("gone") || flag.startsWith("G")) { + rule.setGone(true); + } else if (flag.startsWith("last") || flag.startsWith("L")) { + rule.setLast(true); + } else if (flag.startsWith("next") || flag.startsWith("N")) { + rule.setNext(true); + } else if (flag.startsWith("nocase") || flag.startsWith("NC")) { + rule.setNocase(true); + } else if (flag.startsWith("noescape") || flag.startsWith("NE")) { + rule.setNoescape(true); + } else if (flag.startsWith("proxy") || flag.startsWith("P")) { + // FIXME: Proxy not supported at the moment + //rule.setProxy(true); + } else if (flag.startsWith("qsappend") || flag.startsWith("QSA")) { + rule.setQsappend(true); + } else if (flag.startsWith("redirect") || flag.startsWith("R")) { + if (flag.startsWith("redirect=")) { + flag = flag.substring("redirect=".length()); + rule.setRedirect(true); + rule.setRedirectCode(Integer.parseInt(flag)); + } else if (flag.startsWith("R=")) { + flag = flag.substring("R=".length()); + rule.setRedirect(true); + rule.setRedirectCode(Integer.parseInt(flag)); + } + } else if (flag.startsWith("skip") || flag.startsWith("S")) { + if (flag.startsWith("skip=")) { + flag = flag.substring("skip=".length()); + } else if (flag.startsWith("S=")) { + flag = flag.substring("S=".length()); + } + rule.setSkip(Integer.parseInt(flag)); + } else if (flag.startsWith("type") || flag.startsWith("T")) { + if (flag.startsWith("type=")) { + flag = flag.substring("type=".length()); + } else if (flag.startsWith("T=")) { + flag = flag.substring("T=".length()); + } + rule.setType(true); + rule.setTypeValue(flag); + } else { + throw new IllegalArgumentException("Ivalid flag in: " + line); + } + } + } Modified: trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/Substitution.java =================================================================== --- trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/Substitution.java 2005-10-22 16:24:05 UTC (rev 1434) +++ trunk/labs/jbossweb/src/share/classes/org/jboss/web/rewrite/Substitution.java 2005-10-23 16:31:25 UTC (rev 1435) @@ -200,6 +200,128 @@ } + /** + * Create a substitution with the given string. + */ + /* + public Substitution(String sub, Map maps) { + ArrayList elements = new ArrayList(); + int pos = 0; + int percentPos = 0; + int dollarPos = 0; + + while (pos < sub.length()) { + percentPos = sub.indexOf('%', pos); + dollarPos = sub.indexOf('$', pos); + // FIXME: System.out.println("S: " + sub + " pos: " + pos + " L: " + sub.length() + " %: " + percentPos + " $: " + dollarPos); + if (percentPos == -1 && dollarPos == -1) { + // Static text + StaticElement newElement = new StaticElement(); + newElement.value = sub.substring(pos, sub.length()); + pos = sub.length(); + elements.add(newElement); + } else if (percentPos == -1 || ((dollarPos != -1) && (dollarPos < percentPos))) { + // $: backreference 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))) { + // $: backreference to rule + RewriteRuleBackReferenceElement newElement = new RewriteRuleBackReferenceElement(); + newElement.n = Character.digit(sub.charAt(dollarPos + 1), 10); + pos = dollarPos + 2; + elements.add(newElement); + } else { + // $: map lookup as ${mapname:key|default} + MapElement newElement = new MapElement(); + int open = sub.indexOf('{', dollarPos); + int colon = sub.indexOf(':', dollarPos); + int def = sub.indexOf('|', dollarPos); + int close = sub.indexOf('}', dollarPos); + if (!(-1 < open && open < colon && colon < close)) { + throw new IllegalArgumentException(sub); + } + newElement.map = (RewriteMap) maps.get(sub.substring(open + 1, colon)); + if (newElement.map == null) { + throw new IllegalArgumentException(sub + ": No map: " + sub.substring(open + 1, colon)); + } + if (def > -1) { + if (!(colon < def && def < close)) { + throw new IllegalArgumentException(sub); + } + newElement.key = sub.substring(colon + 1, def); + newElement.defaultValue = sub.substring(def + 1, close); + } else { + newElement.key = sub.substring(colon + 1, close); + } + pos = close + 1; + elements.add(newElement); + } + } else { + // %: backreference to cond 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))) { + // %: backreference to cond + RewriteCondBackReferenceElement newElement = new RewriteCondBackReferenceElement(); + newElement.n = Character.digit(sub.charAt(percentPos + 1), 10); + pos = percentPos + 2; + elements.add(newElement); + } else { + // %: server variable as %{variable} + SubstitutionElement newElement = null; + int open = sub.indexOf('{', percentPos); + int colon = sub.indexOf(':', percentPos); + int close = sub.indexOf('}', percentPos); + if (!(-1 < open && open < close)) { + throw new IllegalArgumentException(sub); + } + if (colon > -1) { + if (!(open < colon && colon < close)) { + throw new IllegalArgumentException(sub); + } + 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(); + ((ServerVariableEnvElement) newElement).key = sub.substring(colon + 1, close); + } else if (type.equals("HTTP")) { + newElement = new ServerVariableHttpElement(); + ((ServerVariableEnvElement) 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); + } + } + } + + this.elements = (SubstitutionElement[]) elements.toArray(new SubstitutionElement[0]); + + } + */ /** * Evaluate the substituation based on the context |