diff --git a/src/helma/framework/RequestBean.java b/src/helma/framework/RequestBean.java index 41876fc0..d2589ad0 100644 --- a/src/helma/framework/RequestBean.java +++ b/src/helma/framework/RequestBean.java @@ -56,7 +56,7 @@ public class RequestBean implements Serializable { return req.getUsername (); } - public Date getLastModified () { + /* public Date getLastModified () { long since = req.getIfModifiedSince (); if (since < 0) return null; @@ -67,7 +67,7 @@ public class RequestBean implements Serializable { public void setLastModified () { throw new RuntimeException ("The lastModified property of the Request object is read-only. "+ "Set lastModified on the Response object if you want to mark the last modification date of a resource."); - } + } */ } diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java index 0ad0313b..89a33acf 100644 --- a/src/helma/framework/RequestTrans.java +++ b/src/helma/framework/RequestTrans.java @@ -26,10 +26,9 @@ public class RequestTrans implements Externalizable { // timestamp of client-cached version, if present in request private long ifModifiedSince = -1; - + // set of ETags the client sent with If-None-Match header + private Set etags; - // this is used to hold the EcmaScript form data object - public transient Object data; // when was execution started on this request? public transient long startTime; @@ -130,6 +129,7 @@ public class RequestTrans implements Externalizable { values = (Map) s.readObject (); httpMethod = s.readByte (); ifModifiedSince = s.readLong (); + etags = (Set) s.readObject (); } /** @@ -141,50 +141,78 @@ public class RequestTrans implements Externalizable { s.writeObject (values); s.writeByte (httpMethod); s.writeLong (ifModifiedSince); + s.writeObject (etags); } public void setIfModifiedSince (long since) { ifModifiedSince = since; } - + public long getIfModifiedSince () { return ifModifiedSince; } - public String getUsername() { - if ( httpUsername!=null ) - return httpUsername; - String auth = (String)get("authorization"); - if ( auth==null || "".equals(auth) ) { - return null; - } - decodeHttpAuth(auth); - return httpUsername; + public void setETags (String etagHeader) { + etags = new HashSet(); + if (etagHeader.indexOf (",") > -1) { + StringTokenizer st = new StringTokenizer (etagHeader, ", \r\n"); + while (st.hasMoreTokens()) + etags.add (st.nextToken ()); + } else { + etags.add (etagHeader); } + } - public String getPassword() { - if ( httpPassword!=null ) - return httpPassword; - String auth = (String)get("authorization"); - if ( auth==null || "".equals(auth) ) { - return null; - } - decodeHttpAuth(auth); - return httpPassword; - } + public Set getETags () { + return etags; + } - private void decodeHttpAuth(String auth) { - if ( auth==null ) - return; - StringTokenizer tok; - if( auth.startsWith("Basic ") ) - tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" ); - else - tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" ); - try { httpUsername = tok.nextToken(); } - catch ( NoSuchElementException e ) { httpUsername = null; } - try { httpPassword = tok.nextToken(); } - catch ( NoSuchElementException e ) { httpPassword = null; } + public boolean hasETag (String etag) { + if (etags == null || etag == null) + return false; + return etags.contains (etag); + } + + public String getUsername() { + if ( httpUsername!=null ) + return httpUsername; + String auth = (String)get("authorization"); + if ( auth==null || "".equals(auth) ) { + return null; } + decodeHttpAuth(auth); + return httpUsername; + } + + public String getPassword() { + if ( httpPassword!=null ) + return httpPassword; + String auth = (String)get("authorization"); + if ( auth==null || "".equals(auth) ) { + return null; + } + decodeHttpAuth(auth); + return httpPassword; + } + + private void decodeHttpAuth(String auth) { + if ( auth==null ) + return; + StringTokenizer tok; + if( auth.startsWith("Basic ") ) + tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" ); + else + tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" ); + try { + httpUsername = tok.nextToken(); + } catch ( NoSuchElementException e ) { + httpUsername = null; + } + try { + httpPassword = tok.nextToken(); + } catch ( NoSuchElementException e ) { + httpPassword = null; + } + } } diff --git a/src/helma/framework/ResponseBean.java b/src/helma/framework/ResponseBean.java index ada43865..96a1ffb5 100644 --- a/src/helma/framework/ResponseBean.java +++ b/src/helma/framework/ResponseBean.java @@ -97,13 +97,6 @@ public class ResponseBean implements Serializable { res.contentType = contentType; } - public void setLastModified (Date date) { - if (date == null) - res.setLastModified (-1); - else - res.setLastModified (date.getTime()); - } - public Map getdata () { return res.getResponseData (); } @@ -143,19 +136,34 @@ public class ResponseBean implements Serializable { public void setstatus (int status) { res.status = status; } - + public Date getLastModified () { long modified = res.getLastModified (); if (modified > -1) return new Date (modified); - else + else return null; } - - public void notModified () throws RedirectException { - res.setNotModified (true); + + public void setLastModified (Date date) { + if (date == null) + res.setLastModified (-1); + else + res.setLastModified (date.getTime()); } + public String getETag () { + return res.getETag (); + } + + public void setETag (String etag) { + res.setETag (etag); + } + + /* public void notModified () throws RedirectException { + res.setNotModified (true); + } */ + } diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java index b05d66c5..4f7f5209 100644 --- a/src/helma/framework/ResponseTrans.java +++ b/src/helma/framework/ResponseTrans.java @@ -54,7 +54,8 @@ public final class ResponseTrans implements Externalizable { private long lastModified = -1; // flag to signal that resource has not been modified private boolean notModified = false; - + // Entity Tag for this response, used for conditional GETs + private String etag = null; // cookies String cookieKeys[]; @@ -85,20 +86,26 @@ public final class ResponseTrans implements Externalizable { static final int INITIAL_BUFFER_SIZE = 2048; - /** - * JavaScript object to make the values Map accessible to - * script code as res.data - */ - public transient Object data; - // the map of form and cookie data private transient Map values; + // the map of macro handlers + private transient Map handlers; + + // the request trans for this response + private transient RequestTrans reqtrans; + public ResponseTrans () { super (); title = head = body = message = error = null; values = new HashMap (); + handlers = new HashMap (); + } + + public ResponseTrans (RequestTrans req) { + this(); + reqtrans = req; } @@ -320,6 +327,15 @@ public final class ResponseTrans implements Externalizable { error = true; response = buffer.toString ().getBytes (); } + // if etag is not set, calc MD5 digest and check it + if (etag == null && !notModified && redir == null) try { + String digest = MD5Encoder.encode (response); + etag = "\""+digest+"\""; + if (reqtrans != null && reqtrans.hasETag (etag)) { + response = new byte[0]; + notModified = true; + } + } catch (Exception ignore) {} buffer = null; // make sure this is done only once, even with more requsts attached } else { response = new byte[0]; @@ -359,17 +375,35 @@ public final class ResponseTrans implements Externalizable { } public void setLastModified (long modified) { + if (modified > -1 && reqtrans != null && + reqtrans.getIfModifiedSince() >= modified) + { + notModified = true; + throw new RedirectException (null); + } lastModified = modified; } - + public long getLastModified () { return lastModified; } - - public void setNotModified (boolean notmod) throws RedirectException { + + /* public void setNotModified (boolean notmod) throws RedirectException { notModified = notmod; if (notmod) throw new RedirectException (null); + } */ + + public void setETag (String value) { + etag = value == null ? null : "\""+value+"\""; + if (etag != null && reqtrans != null && reqtrans.hasETag (etag)) { + notModified = true; + throw new RedirectException (null); + } + } + + public String getETag () { + return etag; } public boolean getNotModified () { @@ -460,6 +494,7 @@ public final class ResponseTrans implements Externalizable { lastModified = s.readLong (); notModified = s.readBoolean (); charset = (String) s.readObject (); + etag = (String) s.readObject (); } public void writeExternal (ObjectOutput s) throws IOException { @@ -476,6 +511,7 @@ public final class ResponseTrans implements Externalizable { s.writeLong (lastModified); s.writeBoolean (notModified); s.writeObject (charset); + s.writeObject (etag); } }