From fd2882e21d3829bda7a75113031a23aee7929ff1 Mon Sep 17 00:00:00 2001 From: hns Date: Thu, 26 Jun 2003 14:10:04 +0000 Subject: [PATCH] Merged changes from helma_1_2 (between helma_1_2_5 and helma_1_2_5_merge_1) --- src/helma/framework/core/Application.java | 18 ++++-- src/helma/framework/core/TypeManager.java | 5 ++ src/helma/objectmodel/db/Node.java | 20 +++--- src/helma/servlet/AbstractServletClient.java | 66 ++++++++++++++------ src/helma/util/CronJob.java | 8 +-- src/helma/util/HtmlEncoder.java | 44 ++++++++++++- src/helma/util/SystemProperties.java | 7 +++ 7 files changed, 130 insertions(+), 38 deletions(-) diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java index 339895d1..962c18bf 100644 --- a/src/helma/framework/core/Application.java +++ b/src/helma/framework/core/Application.java @@ -140,9 +140,9 @@ public final class Application implements IPathElement, Runnable { // the name under which this app serves XML-RPC requests. Defaults to the app name private String xmlrpcHandlerName; - // the list of cron jobs + // the list of currently active cron jobs private Map activeCronJobs = null; - private Vector cronJobs = null; + // the list of custom cron jobs Hashtable customCronJobs = null; /** @@ -342,7 +342,7 @@ public final class Application implements IPathElement, Runnable { public void start() { starttime = System.currentTimeMillis(); worker = new Thread(this, "Worker-" + name); - // worker.setPriority(Thread.NORM_PRIORITY + 2); + worker.setPriority(Thread.NORM_PRIORITY + 1); worker.start(); // logEvent ("session cleanup and scheduler thread started"); @@ -1328,6 +1328,10 @@ public final class Application implements IPathElement, Runnable { } } + // loop-local cron job data + List cronJobs = null; + long lastCronParse = 0; + while (Thread.currentThread() == worker) { long now = System.currentTimeMillis(); @@ -1374,13 +1378,14 @@ public final class Application implements IPathElement, Runnable { } } - if ((cronJobs == null) || (props.lastModified() > lastPropertyRead)) { + if ((cronJobs == null) || (props.lastModified() > lastCronParse)) { updateProperties(); cronJobs = CronJob.parse(props); + lastCronParse = props.lastModified(); } Date d = new Date(); - List jobs = (List) cronJobs.clone(); + List jobs = new ArrayList(cronJobs); jobs.addAll(customCronJobs.values()); CronJob.sort(jobs); @@ -1559,6 +1564,9 @@ public final class Application implements IPathElement, Runnable { private synchronized void updateProperties() { // if so property file has been updated, re-read props. if (props.lastModified() > lastPropertyRead) { + // force property update + props.update(); + // character encoding to be used for responses charset = props.getProperty("charset", "ISO-8859-1"); diff --git a/src/helma/framework/core/TypeManager.java b/src/helma/framework/core/TypeManager.java index b4a54f94..c445c021 100644 --- a/src/helma/framework/core/TypeManager.java +++ b/src/helma/framework/core/TypeManager.java @@ -378,6 +378,11 @@ public final class TypeManager { for (int i = 0; i < list.length; i++) { String fn = list[i].getName(); + // ignore files starting with ".". + if (fn.startsWith(".")) { + continue; + } + if (!proto.updatables.containsKey(fn)) { if (fn.endsWith(templateExtension) || fn.endsWith(scriptExtension) || fn.endsWith(actionExtension) || fn.endsWith(skinExtension) || diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java index 4b43428f..7db843cf 100644 --- a/src/helma/objectmodel/db/Node.java +++ b/src/helma/objectmodel/db/Node.java @@ -1646,12 +1646,12 @@ public final class Node implements INode, Serializable { } // the property does not exist in our propmap - see if we should create it on the fly, - // either because it is mapped to an object from relational database or defined as + // either because it is mapped to an object from relational database or defined as // collection aka virtual node if ((prop == null) && (dbmap != null)) { Relation propRel = dbmap.getPropertyRelation(propname); - // if no property relation is defined for this specific property name, + // if no property relation is defined for this specific property name, // use the generic property relation, if one is defined. if (propRel == null) { propRel = dbmap.getPropertyRelation(); @@ -1668,12 +1668,8 @@ public final class Node implements INode, Serializable { pn.setDbMapping(propRel.getVirtualMapping()); pn.setParent(this); - if (propRel.needsPersistence()) { - setNode(propname, pn); - prop = (Property) propMap.get(propname); - } else { - prop = new Property(propname, this, pn); - } + setNode(propname, pn); + prop = (Property) propMap.get(propname); } // if this is from relational database only fetch if this node // is itself persistent. @@ -2408,6 +2404,14 @@ public final class Node implements INode, Serializable { IProperty next = get((String) e.nextElement()); if ((next != null) && (next.getType() == IProperty.NODE)) { + // check if this property actually needs to be persisted. + if (dbmap != null) { + Relation rel = dbmap.getExactPropertyRelation(next.getName()); + if (rel != null && !rel.needsPersistence()) { + continue; + } + } + Node n = (Node) next.getNodeValue(); if ((n != null) && (n.state == TRANSIENT)) { diff --git a/src/helma/servlet/AbstractServletClient.java b/src/helma/servlet/AbstractServletClient.java index a27e313e..10d5e485 100644 --- a/src/helma/servlet/AbstractServletClient.java +++ b/src/helma/servlet/AbstractServletClient.java @@ -120,7 +120,6 @@ public abstract class AbstractServletClient extends HttpServlet { protected void execute(HttpServletRequest request, HttpServletResponse response, byte method) { RequestTrans reqtrans = new RequestTrans(method); - // get app and path from original request path // String pathInfo = request.getPathInfo (); // String appID = getAppID (pathInfo); @@ -236,23 +235,8 @@ public abstract class AbstractServletClient extends HttpServlet { } } - // check if we need to create a session id. also handle the - // case that the session id doesn't match the remote host address - if ((reqtrans.session == null) || !reqtrans.session.startsWith(remotehost)) { - reqtrans.session = remotehost + "." + - Long.toString(Math.round(Math.random() * Long.MAX_VALUE) - - System.currentTimeMillis(), 36); - - Cookie c = new Cookie("HopSession", reqtrans.session); - - c.setPath("/"); - - if (resCookieDomain != null) { - c.setDomain(resCookieDomain); - } - - response.addCookie(c); - } + // check if session cookie is present and valid, creating it if not. + checkSessionCookie(request, response, reqtrans, resCookieDomain); String browser = request.getHeader("User-Agent"); @@ -448,6 +432,52 @@ public abstract class AbstractServletClient extends HttpServlet { return upload.getParts().get(name); } + /** + * Check if the session cookie is set and valid for this request. + * If not, create a new one. + */ + private void checkSessionCookie(HttpServletRequest request, HttpServletResponse response, + RequestTrans reqtrans, String resCookieDomain) { + // check if we need to create a session id. also handle the + // case that the session id doesn't match the remote host address + StringBuffer b = new StringBuffer(); + addIPAddress(b, request.getRemoteAddr()); + addIPAddress(b, request.getHeader("X-Forwarded-For")); + addIPAddress(b, request.getHeader("Client-ip")); + if ((reqtrans.session == null) || !reqtrans.session.startsWith(b.toString())) { + b.append (Long.toString(Math.round(Math.random() * Long.MAX_VALUE) - + System.currentTimeMillis(), 36)); + + reqtrans.session = b.toString(); + Cookie c = new Cookie("HopSession", reqtrans.session); + + c.setPath("/"); + + if (resCookieDomain != null) { + c.setDomain(resCookieDomain); + } + + response.addCookie(c); + } + } + + /** + * Adds an the 3 most significant bytes of an IP address to the + * session cookie id. + */ + private void addIPAddress(StringBuffer b, String addr) { + if (addr != null) { + int cut = addr.lastIndexOf("."); + if (cut == -1) { + cut = addr.lastIndexOf(":"); + } + if (cut > -1) { + b.append(addr.substring(0, cut+1)); + } + } + } + + /** * Put name value pair in map. * diff --git a/src/helma/util/CronJob.java b/src/helma/util/CronJob.java index b232d852..87b83f98 100644 --- a/src/helma/util/CronJob.java +++ b/src/helma/util/CronJob.java @@ -87,7 +87,7 @@ public class CronJob { private String name = null; private String function = null; - private long timeout = 20000; + private long timeout = 600000; /** A method for parsing properties. It looks through the properties * file for entries that look like this: @@ -182,7 +182,7 @@ public class CronJob { } - public static Vector parse(Properties props) { + public static List parse(Properties props) { Hashtable jobs = new Hashtable (); Enumeration e = props.keys (); while (e.hasMoreElements ()) { @@ -222,8 +222,8 @@ public class CronJob { } catch (NoSuchElementException nsee) { } } - Vector jobVec = new Vector (jobs.values ()); - return (Vector) sort (jobVec); + List jobVec = new ArrayList (jobs.values ()); + return sort (jobVec); } public static List sort (List list) { diff --git a/src/helma/util/HtmlEncoder.java b/src/helma/util/HtmlEncoder.java index 9c1bb6c4..6f4f69f6 100644 --- a/src/helma/util/HtmlEncoder.java +++ b/src/helma/util/HtmlEncoder.java @@ -342,6 +342,11 @@ public final class HtmlEncoder { emptyTags.add("param"); } + final static byte TAG_NAME = 0; + final static byte TAG_SPACE = 1; + final static byte TAG_ATT_NAME = 2; + final static byte TAG_ATT_VAL = 3; + /** * Do "smart" encodging on a string. This means that valid HTML entities and tags, @@ -397,6 +402,8 @@ public final class HtmlEncoder { // are we inside an HTML tag? boolean insideHtmlTag = false; + boolean insideCloseTag = false; + byte htmlTagMode = TAG_NAME; // if we are inside a tag, we encode everything to make // documentation work easier @@ -445,7 +452,7 @@ public final class HtmlEncoder { } } else if (!insideTag) { // check if this is a HTML tag. - boolean insideCloseTag = ('/' == str.charAt(i + 1)); + insideCloseTag = ('/' == str.charAt(i + 1)); int tagStart = insideCloseTag ? (i + 2) : (i + 1); int j = tagStart; @@ -464,6 +471,7 @@ public final class HtmlEncoder { allTags.contains(tagName) && !insideCodeTag) { insideHtmlTag = insideTag = true; htmlQuoteChar = '\u0000'; + htmlTagMode = TAG_NAME; // set ignoreNewline on some tags, depending on wheather they're // being opened or closed. @@ -610,6 +618,7 @@ public final class HtmlEncoder { escape = false; } else if (htmlQuoteChar == c) { htmlQuoteChar = '\u0000'; + htmlTagMode = TAG_SPACE; } else if (htmlQuoteChar == '\u0000') { htmlQuoteChar = c; } @@ -650,7 +659,11 @@ public final class HtmlEncoder { // Check if this is an empty tag so we don't generate an // additional tag. if (str.charAt(i - 1) == '/') { - openTags.pop(); + // this is to avoid misinterpreting tags like + // as empty + if (htmlTagMode != TAG_ATT_VAL && htmlTagMode != TAG_ATT_NAME) { + openTags.pop(); + } } } else { ret.append(">"); @@ -663,7 +676,32 @@ public final class HtmlEncoder { default: - // ret.append (c); + if (insideHtmlTag && !insideCloseTag) { + switch(htmlTagMode) { + case TAG_NAME: + if (!Character.isLetterOrDigit(c)) { + htmlTagMode = TAG_SPACE; + } + break; + case TAG_SPACE: + if (Character.isLetterOrDigit(c)) { + htmlTagMode = TAG_ATT_NAME; + } + break; + case TAG_ATT_NAME: + if (c == '=') { + htmlTagMode = TAG_ATT_VAL; + } else if (c == ' ') { + htmlTagMode = TAG_SPACE; + } + break; + case TAG_ATT_VAL: + if (Character.isWhitespace(c) && htmlQuoteChar == '\u0000') { + htmlTagMode = TAG_SPACE; + } + break; + } + } if (c < 128) { ret.append(c); } else if ((c >= 128) && (c < 256)) { diff --git a/src/helma/util/SystemProperties.java b/src/helma/util/SystemProperties.java index 6dbc9811..8c70c8fb 100644 --- a/src/helma/util/SystemProperties.java +++ b/src/helma/util/SystemProperties.java @@ -101,6 +101,13 @@ public final class SystemProperties extends Properties { return Math.max(file.lastModified(), lastadd); } + /** + * Update/re-read the properties from file if necessary. + */ + public void update () { + checkFile(); + } + /** * Return a checksum that changes when something in the properties changes. */