/* * PhoneFilter.java * * Brazil project web application toolkit, * export version: 2.3 * Copyright (c) 2007-2009 Sun Microsystems, Inc. * * Sun Public License Notice * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is included as the file "license.terms", * and also available at http://www.sun.com/ * * The Original Code is from: * Brazil project web application toolkit release 2.3. * The Initial Developer of the Original Code is: suhler. * Portions created by suhler are Copyright (C) Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): suhler. * * Version: 1.4 * Created by suhler on 07/06/07 * Last modified by suhler on 09/01/30 16:37:41 * * Version Histories: * * 1.4 09/01/30-16:37:41 (suhler) * diag changes * * 1.3 07/06/25-11:19:33 (suhler) * bunches of fixes: * - content encoding * - character set encoding * - better html context determination * * 1.2 07/06/07-11:33:59 (suhler) * doc updates * * 1.2 70/01/01-00:00:02 (Codemgr) * SunPro Code Manager data about conflicts, renames, etc... * Name history : 1 0 sunlabs/PhoneFilter.java * * 1.1 07/06/07-11:28:29 (suhler) * date and time created 07/06/07 11:28:29 by suhler * */ package sunlabs.brazil.filter; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.StringTokenizer; import java.util.Hashtable; import java.util.Enumeration; import sunlabs.brazil.server.Request; import sunlabs.brazil.server.Server; import sunlabs.brazil.util.Format; import sunlabs.brazil.util.LexML; import sunlabs.brazil.util.http.HttpInputStream; import sunlabs.brazil.util.http.HttpUtil; import sunlabs.brazil.util.http.MimeHeaders; import sunlabs.brazil.util.http.HttpRequest; import sunlabs.brazil.util.regexp.Regexp; import sunlabs.brazil.handler.HtmlRewriter; /** * Rewrite text between markup (and not in links) based on re sub's *
*
re
regular 'phone' expression. Phone Expressions are simplified * regular expressions: *
sub
substitution *
trailer
to add at end of document (before ) *
*/ public class PhoneFilter implements Filter { String prefix; // our properties prefix String sub; // the substitution string Regexp re; // the regular expression to match String trailer; // text to add at end of all rewritten content Server server; public boolean init(Server server, String prefix) { this.prefix = prefix; this.server=server; boolean noCase = true; sub = server.props.getProperty(prefix + "sub", ""); trailer = server.props.getProperty(prefix + "trailer"); String reString = server.props.getProperty(prefix + "re"); try { String r= getRe(reString); server.log(Server.LOG_DIAGNOSTIC, prefix, r); re = new Regexp(r, noCase); } catch (IllegalArgumentException e) { server.log(Server.LOG_WARNING, prefix, "Invalid regexp"); return false; } server.log(Server.LOG_DIAGNOSTIC, prefix, "Installed"); return true; } /** * Remove any accept-encoding headers so we don't have do * decode them ourselves. */ public boolean respond(Request request) { request.headers.remove("accept-encoding"); request.log(Server.LOG_DIAGNOSTIC, prefix, request.url); return false; } /** * Only filter html files */ public boolean shouldFilter(Request request, MimeHeaders headers) { String type = headers.get("content-type"); request.log(Server.LOG_DIAGNOSTIC, prefix, request.url + ": " + type); return type!=null && type.startsWith("text/html"); } public byte[] filter(Request request, MimeHeaders headers, byte[] content) { HtmlRewriter hr = null; String encoding = HttpRequest.getEncoding(headers); try { hr = new HtmlRewriter(new String(content, encoding)); } catch (UnsupportedEncodingException e) { hr = new HtmlRewriter(new String(content)); request.log(Server.LOG_WARNING, "bad encoding: " + encoding); } CountEntities ce = new CountEntities("a head style script", "p div table tr td"); boolean isChanged = false; request.log(Server.LOG_DIAGNOSTIC, prefix, "filtering: " + request.url); while (hr.nextToken()) { int type = hr.getType(); if (type == LexML.TAG) { String tag = hr.getTag(); // lower case tag ce.found(tag); if (trailer!=null && tag.equals("/body") && isChanged) { hr.append(Format.subst(request.props,trailer)); request.log(Server.LOG_DIAGNOSTIC, "adding trailer"); hr.appendToken(); } } else if (type==LexML.STRING) { if (process(hr, ce.getValue())) isChanged=true; } } if (isChanged) { try { request.log(Server.LOG_DIAGNOSTIC, prefix + "modified markup"); return hr.toString().getBytes(encoding); } catch (UnsupportedEncodingException e) { request.log(Server.LOG_WARNING, "bad encoding: " + encoding); return hr.toString().getBytes(); } } else { request.log(Server.LOG_DIAGNOSTIC, prefix + "markup unchanged"); return content; } } /** * Process literal text for rewriting * @param hr current rewrite context * @param count html parse state (0=rewrite) */ boolean process(HtmlRewriter hr, int count) { String src = hr.getToken(); String result = re.subAll(src, sub); if (result.equals(src)) { return false; } else if (count == 0) { server.log(Server.LOG_DIAGNOSTIC, prefix, "(" + src.trim() + ") => (" + result.trim() + ")"); hr.append(result); return true; } else { server.log(Server.LOG_DIAGNOSTIC, prefix, "(" + src.trim() + ") !=> (" + result.trim() + ")"); return false; } } /** * Turn a "phone" regular expression into a real RE. */ public static String getRe(String s) { StringBuffer sb = new StringBuffer(); char c; for(int i = 0; i 0) { total=0; Enumeration e = ht.elements(); while(e.hasMoreElements()) { ((Value) e.nextElement()).reset(); } } } // found a tag, deal with it void found(String s) { if (resets.get(s) != null) { resetAll(); return; } boolean gotSlash=false; Value value; if (s.startsWith("/")) { gotSlash=true; value = (Value) ht.get(s.substring(1)); } else { value = (Value) ht.get(s); } if (value != null) { total += value.nudge(gotSlash); if (total < 0) total=0; } } int getValue() { return total; } } /** * A simple counter class */ static class Value { int v; public Value() { v = 0; } public int nudge(boolean isMinus) { v += isMinus ? -1 : 1; if (v < 0) { v = 0; return 0; } return isMinus ? -1 : 1; } public void reset() { v=0; } public String toString() { return "" + v; } } }